Idempotency in System Designing

expert · System Designing

Idempotency is a property of an operation where executing it multiple times yields the exact same system state and outcome as executing it a single time. In distributed systems, where network failures, timeouts, and automatic retries are standard operational realities, designing endpoints to be idempotent is critical to ensuring data consistency and preventing duplicate transactions. 1. The Core Problem: The Network Timeout Blindspot When a client sends a request to a server, three things must happen over a network wire: The client sends the request. The server processes the request and updates its state (e.g., charges a card). The server sends a response back to the client. If a network glitch or timeout occurs during Step 3 , the client is left entirely blind. The server successfully processed the payment, but the client thinks the connection dropped. If the client automatically retries the request without idempotency protection, the server will execute the operation a second time, charging the customer twice. 2. HTTP Methods and Idempotency Specs The HTTP protocol specifies standard idempotency expectations for default request types: HTTP Method Idempotent? Technical Behavior GET Yes Reads data without mutating state. Calling GET /users/1 a thousand times changes nothing. PUT Yes Replaces a resource entirely. Updating an address to "Main St" repeatedly leaves the address as "Main St". DELETE Yes Removes a resource. Deleting DELETE /orders/50 the first time removes it ( 200  OK ). Subsequent deletes change nothing ( 404  Not Found ), but the state of the server remains identical—the item stays gone. POST No Creates resources or appends data. Executing POST /orders five times will mistakenly create five distinct orders. 3. Implementation Blueprint: Idempotency Keys To make non-idempotent operations (like POST requests for payments or order creations) completely safe, systems use an Idempotency Key mechanism. The Step-by-Step Workflow: Client Generation: Before firing a critical request, the client generates a unique, single-use string token—typically a UUIDv4 (e.g., idempotency-key: 9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d ) and passes it inside the HTTP headers. Server Check: The server intercepts the request and attempts to save the key to an ultra-fast, centralized in-memory cache (like Redis ) using an atomic set-if-not-exists lock command (like SETNX or a distributed lock mechanism like Redlock) with a defined Time-To-Live (TTL, e.g., 24 hours). Scenario A (First Request): The key does not exist in Redis. The server locks the key, flags its status as IN_PROGRESS , processes the complex business logic (e.g., charges the payment gateway), stores the final response payload in Redis alongside the key, updates the status to COMPLETED , and returns the response to the client. Scenario B (The Retry/Duplicate): Due to an earlier network timeout, the client sends the exact same request with the exact same idempotency key. The server looks up Redis and finds the key already exists: If the status is IN_PROGRESS , it returns an error or a 409 Conflict (telling the client a twin request is already executing). If the status is COMPLETED , the server completely bypasses the business and payment logic. It simply reads the cached response payload directly out of Redis and feeds it back to the client instantly. The customer is charged exactly once. 4. System Design Takeaways Isolate Downstream Side Effects: If your microservice calls an external third-party service (like Stripe, SendGrid, or Twilio) inside your request pipeline, you must pass your internal idempotency key forward to their API as well. If your internal database transaction rolls back, but you already fired a non-idempotent call to an external vendor, your system state splits. Storage Eviction: Idempotency keys do not need to be stored in your primary database forever. Storing them in Redis with a 24-to-48-hour TTL is usually more than enough to guard against immediate automated client retries while keeping storage overhead lightweight. Idempotent Consumers: When using Message Queues with an "At-Least-Once" delivery guarantee, background workers (consumers) will occasionally receive duplicate messages. The worker code must treat the unique message tracking ID as an idempotency key, checking a local database or cache before executing any database mutations.

Back to System Designing

Browse all study material on Careeroza