63 lines
2 KiB
Markdown
63 lines
2 KiB
Markdown
|
|
# ADR 001: Idempotency for Critical Write Operations
|
||
|
|
|
||
|
|
## Status
|
||
|
|
|
||
|
|
Accepted
|
||
|
|
|
||
|
|
## Context
|
||
|
|
|
||
|
|
Repeated requests (retries/double clicks) can currently create duplicate offers/acceptances. This is problematic because:
|
||
|
|
|
||
|
|
- Users may accidentally double-click buttons
|
||
|
|
- Network issues might cause requests to timeout and be retried
|
||
|
|
- The system should behave deterministically when handling retries
|
||
|
|
|
||
|
|
## Decision
|
||
|
|
|
||
|
|
We implement idempotency key handling for critical POST endpoints:
|
||
|
|
1. Add `x-idempotency-key` header support to POST endpoints
|
||
|
|
2. Store request results in a database table for replaying responses
|
||
|
|
3. Return cached responses for identical keys
|
||
|
|
4. Apply this to the most critical endpoints:
|
||
|
|
- `/offers/:requestId`
|
||
|
|
- `/offers/negotiation/:offerId`
|
||
|
|
- `/offers/accept/:offerId`
|
||
|
|
- `/help-requests`
|
||
|
|
|
||
|
|
## Consequences
|
||
|
|
|
||
|
|
### Positive
|
||
|
|
- Eliminates duplicate offers/acceptances from retries
|
||
|
|
- Makes critical endpoints behave deterministically on retries
|
||
|
|
- Improves user experience by preventing accidental duplicates
|
||
|
|
- Follows REST best practices for idempotent operations
|
||
|
|
|
||
|
|
### Negative
|
||
|
|
- Adds complexity to request handling
|
||
|
|
- Requires database storage for idempotency keys
|
||
|
|
- Slight performance overhead for idempotent requests
|
||
|
|
|
||
|
|
## Implementation Details
|
||
|
|
|
||
|
|
### Database Schema
|
||
|
|
Added `idempotency_keys` table with:
|
||
|
|
- `key`: Unique identifier for the request (VARCHAR)
|
||
|
|
- `response_body`: Cached response data (TEXT)
|
||
|
|
- `created_at`: Timestamp of when the key was first used
|
||
|
|
|
||
|
|
### Middleware
|
||
|
|
Created `requireIdempotencyKey` middleware that:
|
||
|
|
1. Checks for `x-idempotency-key` header in POST requests
|
||
|
|
2. If key exists, checks if it has been used before
|
||
|
|
3. If used before, returns cached response
|
||
|
|
4. If new, stores the request and caches the eventual response
|
||
|
|
|
||
|
|
### Endpoints
|
||
|
|
Applied to critical write operations:
|
||
|
|
- POST `/offers/:requestId`
|
||
|
|
- POST `/offers/negotiation/:offerId`
|
||
|
|
- POST `/offers/accept/:offerId`
|
||
|
|
- POST `/help-requests`
|
||
|
|
|
||
|
|
## Testing
|
||
|
|
Added tests for idempotency behavior in the existing test suite.
|