DEV Community

Mohamed_Yahya
Mohamed_Yahya

Posted on

Retries Are Not Reliability: Understanding Idempotency in Distributed Systems

๐—œ๐—ป๐˜๐—ฟ๐—ผ๐—ฑ๐˜‚๐—ฐ๐˜๐—ถ๐—ผ๐—ป

Modern software systems expect failures to happen. Networks can timeout, servers can restart, and requests can fail halfway through execution.

To recover from these failures, systems commonly use retries.

But retries introduce another problem: the same operation may execute more than once.

So the important question becomes:

If an operation runs twice, can our system safely handle it?

This is where idempotency becomes an important software-engineering concept.


๐—ง๐—ต๐—ฒ ๐—ฅ๐—ฒ๐—ฎ๐—น ๐—ฃ๐—ฟ๐—ผ๐—ฏ๐—น๐—ฒ๐—บ: ๐—” ๐—ง๐—ถ๐—บ๐—ฒ๐—ผ๐˜‚๐˜ ๐——๐—ผ๐—ฒ๐˜€๐—ป'๐˜ ๐— ๐—ฒ๐—ฎ๐—ป ๐—™๐—ฎ๐—ถ๐—น๐˜‚๐—ฟ๐—ฒ

Imagine a payment request reaches the server and the payment succeedsโ€”but the response is lost because of a network problem.

Client
โ†“
Request
โ†“
Server
โ†“
Payment succeeds
โ†“
Response lost
โ†“
Client timeout

The client doesn't know whether the operation failed or succeeded.

So it retriesโ€”and the same operation may happen again.

The real challenge isn't retrying. It's making retries safe.

Client retrying a request after the server succeeds but the response is lost


๐—ช๐—ต๐—ฎ๐˜ ๐—œ๐˜€ ๐—œ๐—ฑ๐—ฒ๐—บ๐—ฝ๐—ผ๐˜๐—ฒ๐—ป๐—ฐ๐˜†?

Idempotency means that repeating the same operation produces the same intended final state as performing it once.

For example:

Set account status = ACTIVE

Whether we run it once or five times, the final state is still:

ACTIVE

But consider:

Add โ‚น100 to account

Running it five times adds โ‚น500.

So the important idea is:

If a request is retried, the system should not accidentally repeat the business effect.

This is why idempotency is important when designing reliable software.

Server checking an idempotency key and returning the previous result for a repeated request


๐—œ๐—ฑ๐—ฒ๐—บ๐—ฝ๐—ผ๐˜๐—ฒ๐—ป๐˜ ๐˜ƒ๐˜€ ๐—ก๐—ผ๐—ป-๐—œ๐—ฑ๐—ฒ๐—บ๐—ฝ๐—ผ๐˜๐—ฒ๐—ป๐˜ ๐—ข๐—ฝ๐—ฒ๐—ฟ๐—ฎ๐˜๐—ถ๐—ผ๐—ป๐˜€

Not every operation is automatically idempotent.

A simple example of an idempotent operation is:

Set user status = ACTIVE

Running it multiple times still produces:

ACTIVE

A non-idempotent operation changes the result every time it runs:

Add โ‚น100 to balance

Run once โ†’ โ‚น100 added
Run twice โ†’ โ‚น200 added
Run three times โ†’ โ‚น300 added

So when designing a system, we need to ask:

"What happens if this operation runs again?"

๐—ฆ๐—ถ๐—บ๐—ฝ๐—น๐—ฒ ๐—ฑ๐—ถ๐—ฎ๐—ด๐—ฟ๐—ฎ๐—บ:

             Operation
                โ”‚
         โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”
         โ†“             โ†“
    Idempotent     Non-idempotent
         โ”‚             โ”‚
   Same result     Result changes
   when repeated   when repeated
Enter fullscreen mode Exit fullscreen mode

๐—ช๐—ต๐˜† ๐—ฅ๐—ฒ๐˜๐—ฟ๐—ถ๐—ฒ๐˜€ ๐—–๐—ฎ๐—ป ๐—–๐—ฟ๐—ฒ๐—ฎ๐˜๐—ฒ ๐——๐˜‚๐—ฝ๐—น๐—ถ๐—ฐ๐—ฎ๐˜๐—ฒ ๐—ข๐—ฝ๐—ฒ๐—ฟ๐—ฎ๐˜๐—ถ๐—ผ๐—ป๐˜€

Retries are useful because temporary failures are common in real systems.

Request
โ†“
Temporary failure
โ†“
Retry
โ†“
Success

The problem starts when the first request actually succeeded, but the client never received the response.

First request โ†’ Operation succeeds โ†’ Response lost
โ†“
Client retries
โ†“
Operation runs again

The same problem can happen at different layers: clients, APIs, load balancers, message queues, and background workers can all retry work.

Retries ๐—ถ๐—บ๐—ฝ๐—ฟ๐—ผ๐˜ƒ๐—ฒ ๐—ฟ๐—ฒ๐—น๐—ถ๐—ฎ๐—ฏ๐—ถ๐—น๐—ถ๐˜๐˜†, but without idempotency, they can also create duplicate work.


๐—œ๐—ฑ๐—ฒ๐—บ๐—ฝ๐—ผ๐˜๐—ฒ๐—ป๐—ฐ๐˜† ๐—ž๐—ฒ๐˜†๐˜€: ๐—š๐—ถ๐˜ƒ๐—ถ๐—ป๐—ด ๐—ฎ ๐—ฅ๐—ฒ๐—พ๐˜‚๐—ฒ๐˜€๐˜ ๐—ฎ๐—ป ๐—œ๐—ฑ๐—ฒ๐—ป๐˜๐—ถ๐˜๐˜†

One common way to make non-idempotent operations safer is to give each request a unique idempotency key.

For example:

Idempotency-Key: payment-abc123

The server stores this key when it successfully processes the request.

If the same request arrives again:

Same key
โ†“
Already processed?
โ†“
YES โ†’ Return the previous result

Instead of creating another payment or order, the system recognizes that it has already handled that request.

The key idea is simple:

The request can be repeated, but the business operation should happen only once.

๐—œ๐—ฑ๐—ฒ๐—บ๐—ฝ๐—ผ๐˜๐—ฒ๐—ป๐—ฐ๐˜† ๐—ž๐—ฒ๐˜†๐˜€: ๐—š๐—ถ๐˜ƒ๐—ถ๐—ป๐—ด ๐—ฎ ๐—ฅ๐—ฒ๐—พ๐˜‚๐—ฒ๐˜€๐˜ ๐—ฎ๐—ป ๐—œ๐—ฑ๐—ฒ๐—ป๐˜๐—ถ๐˜๐˜†


๐—›๐—ผ๐˜„ ๐—œ๐—ฑ๐—ฒ๐—บ๐—ฝ๐—ผ๐˜๐—ฒ๐—ป๐—ฐ๐˜† ๐—ž๐—ฒ๐˜†๐˜€ ๐—”๐—ฐ๐˜๐˜‚๐—ฎ๐—น๐—น๐˜† ๐—ช๐—ผ๐—ฟ๐—ธ

The basic flow is:

Client
โ†“
Request + Idempotency Key
โ†“
Server
โ†“
Check stored key

If the key doesn't exist, the server processes the operation and stores the result.

If the same key appears again for the same operation, the server can recognize it as a repeated request and return the stored result.

New key โ†’ Process โ†’ Store result

Same key โ†’ Find result โ†’ Return result

This approach is useful for operations such as payments, order creation, job submission, and other requests where duplicate execution could cause a problem.

Idempotency keys turn an ๐—ผ๐˜๐—ต๐—ฒ๐—ฟ๐˜„๐—ถ๐˜€๐—ฒ ๐—ฎ๐—บ๐—ฏ๐—ถ๐—ด๐˜‚๐—ผ๐˜‚๐˜€ ๐—ฟ๐—ฒ๐˜๐—ฟ๐˜† ๐—ถ๐—ป๐˜๐—ผ ๐—ฎ ๐—ฟ๐—ฒ๐—พ๐˜‚๐—ฒ๐˜€๐˜ ๐˜๐—ต๐—ฒ ๐˜€๐˜†๐˜€๐˜๐—ฒ๐—บ ๐—ฐ๐—ฎ๐—ป ๐—ฟ๐—ฒ๐—ฐ๐—ผ๐—ด๐—ป๐—ถ๐˜‡๐—ฒ.


๐—œ๐—ฑ๐—ฒ๐—บ๐—ฝ๐—ผ๐˜๐—ฒ๐—ป๐—ฐ๐˜† ๐—ฎ๐—ป๐—ฑ ๐——๐—ฎ๐˜๐—ฎ๐—ฏ๐—ฎ๐˜€๐—ฒ ๐——๐—ฒ๐˜€๐—ถ๐—ด๐—ป

An idempotency key is useful only if the system can reliably remember it.

A simple approach is to store the key in the database:

idempotency_key


payment-abc123

When another request arrives with the same key, the system can detect that the operation was already processed.

But checking the key in application code alone is not enough. Two identical requests can arrive at almost the same time.

That's why the database should also enforce uniqueness, for example with a ๐˜‚๐—ป๐—ถ๐—พ๐˜‚๐—ฒ ๐—ฐ๐—ผ๐—ป๐˜€๐˜๐—ฟ๐—ฎ๐—ถ๐—ป๐˜.

Application logic can detect duplicates, but the database should provide the final protection against duplicate records.


๐—ฅ๐—ฎ๐—ฐ๐—ฒ ๐—–๐—ผ๐—ป๐—ฑ๐—ถ๐˜๐—ถ๐—ผ๐—ป๐˜€: ๐—ช๐—ต๐—ฒ๐—ป ๐—ง๐˜„๐—ผ ๐—ฅ๐—ฒ๐—พ๐˜‚๐—ฒ๐˜€๐˜๐˜€ ๐—”๐—ฟ๐—ฟ๐—ถ๐˜ƒ๐—ฒ ๐—ง๐—ผ๐—ด๐—ฒ๐˜๐—ต๐—ฒ๐—ฟ

Now consider two requests using the same idempotency key at almost exactly the same time.

Request A โ”€โ”€โ†’ Check key โ†’ Not found

Request B โ”€โ”€โ†’ Check key โ†’ Not found

Both requests may think they are allowed to continue.

This is called a race condition: the result depends on the timing of concurrent operations.

A unique database constraint can prevent both requests from creating the same record.

Request A โ”€โ”€โ†’ Database โ”€โ”€โ†’ INSERT โœ“

Request B โ”€โ”€โ†’ Database โ”€โ”€โ†’ DUPLICATE โœ—

The important lesson is:

๐—–๐—ต๐—ฒ๐—ฐ๐—ธ๐—ถ๐—ป๐—ด ๐—ณ๐—ถ๐—ฟ๐˜€๐˜ ๐—ฎ๐—ป๐—ฑ ๐—ถ๐—ป๐˜€๐—ฒ๐—ฟ๐˜๐—ถ๐—ป๐—ด ๐—น๐—ฎ๐˜๐—ฒ๐—ฟ ๐—ถ๐˜€ ๐—ป๐—ผ๐˜ ๐—ฎ๐—น๐˜„๐—ฎ๐˜†๐˜€ ๐˜€๐—ฎ๐—ณ๐—ฒ ๐˜„๐—ต๐—ฒ๐—ป ๐—บ๐˜‚๐—น๐˜๐—ถ๐—ฝ๐—น๐—ฒ ๐—ฟ๐—ฒ๐—พ๐˜‚๐—ฒ๐˜€๐˜๐˜€ ๐—ฐ๐—ฎ๐—ป ๐—ฟ๐˜‚๐—ป ๐—ฎ๐˜ ๐˜๐—ต๐—ฒ ๐˜€๐—ฎ๐—บ๐—ฒ ๐˜๐—ถ๐—บ๐—ฒ.

Concurrency needs to be handled deliberately.

Race Condition


๐—œ๐—ฑ๐—ฒ๐—บ๐—ฝ๐—ผ๐˜๐—ฒ๐—ป๐—ฐ๐˜† ๐—ถ๐—ป ๐—ค๐˜‚๐—ฒ๐˜‚๐—ฒ-๐—•๐—ฎ๐˜€๐—ฒ๐—ฑ ๐—ฆ๐˜†๐˜€๐˜๐—ฒ๐—บ๐˜€

Idempotency is not limited to HTTP APIs. It is equally important in background job processing.

Consider a worker processing a job:

Queue
โ†“
Worker
โ†“
Process job
โ†“
Worker fails
โ†“
Job is retried

The retry may cause the worker to process the same job again.

For example, a worker might successfully update the database and then crash before confirming that the job finished.

The queue may then deliver the job again.

This means a reliable worker should be designed so that ๐—ฝ๐—ฟ๐—ผ๐—ฐ๐—ฒ๐˜€๐˜€๐—ถ๐—ป๐—ด ๐˜๐—ต๐—ฒ ๐˜€๐—ฎ๐—บ๐—ฒ ๐—ท๐—ผ๐—ฏ ๐—บ๐—ผ๐—ฟ๐—ฒ ๐˜๐—ต๐—ฎ๐—ป ๐—ผ๐—ป๐—ฐ๐—ฒ ๐—ฑ๐—ผ๐—ฒ๐˜€ ๐—ป๐—ผ๐˜ ๐—ฐ๐—ฟ๐—ฒ๐—ฎ๐˜๐—ฒ ๐—ฎ๐—ป ๐—ถ๐—ป๐—ฐ๐—ผ๐—ฟ๐—ฟ๐—ฒ๐—ฐ๐˜ ๐—ณ๐—ถ๐—ป๐—ฎ๐—น ๐˜€๐˜๐—ฎ๐˜๐—ฒ.

This is one reason idempotency is important in systems built with ๐—พ๐˜‚๐—ฒ๐˜‚๐—ฒ๐˜€, ๐˜„๐—ผ๐—ฟ๐—ธ๐—ฒ๐—ฟ๐˜€, ๐—ฟ๐—ฒ๐˜๐—ฟ๐—ถ๐—ฒ๐˜€, ๐—ฎ๐—ป๐—ฑ ๐—ฎ๐˜€๐˜†๐—ป๐—ฐ๐—ต๐—ฟ๐—ผ๐—ป๐—ผ๐˜‚๐˜€ ๐—ฝ๐—ฟ๐—ผ๐—ฐ๐—ฒ๐˜€๐˜€๐—ถ๐—ป๐—ด.


๐—œ๐—ฑ๐—ฒ๐—บ๐—ฝ๐—ผ๐˜๐—ฒ๐—ป๐—ฐ๐˜† ๐—œ๐˜€ ๐—ก๐—ผ๐˜ ๐˜๐—ต๐—ฒ ๐—ฆ๐—ฎ๐—บ๐—ฒ ๐—ฎ๐˜€ ๐—˜๐˜…๐—ฎ๐—ฐ๐˜๐—น๐˜†-๐—ข๐—ป๐—ฐ๐—ฒ ๐—˜๐˜…๐—ฒ๐—ฐ๐˜‚๐˜๐—ถ๐—ผ๐—ป

Idempotency does not mean the system physically executes an operation only once.

A request or job may actually be processed more than once.

The goal is different:

๐— ๐˜‚๐—น๐˜๐—ถ๐—ฝ๐—น๐—ฒ ๐—ฒ๐˜…๐—ฒ๐—ฐ๐˜‚๐˜๐—ถ๐—ผ๐—ป๐˜€ ๐˜€๐—ต๐—ผ๐˜‚๐—น๐—ฑ ๐—ป๐—ผ๐˜ ๐—ฐ๐—ฟ๐—ฒ๐—ฎ๐˜๐—ฒ ๐—บ๐˜‚๐—น๐˜๐—ถ๐—ฝ๐—น๐—ฒ ๐—ฏ๐˜‚๐˜€๐—ถ๐—ป๐—ฒ๐˜€๐˜€ ๐—ฒ๐—ณ๐—ณ๐—ฒ๐—ฐ๐˜๐˜€.

Execute โ†’ Execute โ†’ Execute
โ†“
Same intended final state

This distinction is important in distributed systems because guaranteeing that something happens exactly once across multiple systems can be difficult.

Instead, engineers often design operations to be ๐˜€๐—ฎ๐—ณ๐—ฒ ๐˜„๐—ต๐—ฒ๐—ป ๐—ฟ๐—ฒ๐—ฝ๐—ฒ๐—ฎ๐˜๐—ฒ๐—ฑ.


๐—œ๐—ฑ๐—ฒ๐—บ๐—ฝ๐—ผ๐˜๐—ฒ๐—ป๐—ฐ๐˜† ๐—ถ๐—ป ๐—ฅ๐—ฒ๐—ฎ๐—น ๐—ฆ๐—ผ๐—ณ๐˜๐˜„๐—ฎ๐—ฟ๐—ฒ ๐—ฆ๐˜†๐˜€๐˜๐—ฒ๐—บ๐˜€

Idempotency is useful anywhere a repeated request could create an unwanted result.

Common examples include:

Creating an order
Processing a payment
Submitting a background job
Sending notifications
Updating user information
Handling webhook events

The implementation can differ between systems, but the principle remains the same:

Same operation
โ†“
Repeated request
โ†“
Safe final result

This makes the system more reliable when requests are retried or messages are delivered more than once.


๐—ง๐—ต๐—ฒ ๐—˜๐—ป๐—ด๐—ถ๐—ป๐—ฒ๐—ฒ๐—ฟ๐—ถ๐—ป๐—ด ๐— ๐—ถ๐—ป๐—ฑ๐˜€๐—ฒ๐˜: ๐——๐—ฒ๐˜€๐—ถ๐—ด๐—ป ๐—ณ๐—ผ๐—ฟ ๐—ฅ๐—ฒ๐—ฝ๐—ฒ๐˜๐—ถ๐˜๐—ถ๐—ผ๐—ป

The biggest lesson is not simply "use an idempotency key."

The deeper lesson is to design software with the assumption that requests may be repeated.

Before implementing an operation, ask:

What if this request runs twice?
What if it runs three times?
What if the response is lost?
What if two requests arrive together?

These questions help us discover duplicate operations, race conditions, and data-consistency problems before they become production issues.

๐—ฅ๐—ฒ๐—น๐—ถ๐—ฎ๐—ฏ๐—น๐—ฒ ๐˜€๐—ผ๐—ณ๐˜๐˜„๐—ฎ๐—ฟ๐—ฒ ๐—ถ๐˜€ ๐—ป๐—ผ๐˜ ๐˜€๐—ผ๐—ณ๐˜๐˜„๐—ฎ๐—ฟ๐—ฒ ๐˜๐—ต๐—ฎ๐˜ ๐—ป๐—ฒ๐˜ƒ๐—ฒ๐—ฟ ๐—ณ๐—ฎ๐—ถ๐—น๐˜€. ๐—œ๐˜ ๐—ถ๐˜€ ๐˜€๐—ผ๐—ณ๐˜๐˜„๐—ฎ๐—ฟ๐—ฒ ๐˜๐—ต๐—ฎ๐˜ ๐—ฏ๐—ฒ๐—ต๐—ฎ๐˜ƒ๐—ฒ๐˜€ ๐˜€๐—ฎ๐—ณ๐—ฒ๐—น๐˜† ๐˜„๐—ต๐—ฒ๐—ป ๐—ณ๐—ฎ๐—ถ๐—น๐˜‚๐—ฟ๐—ฒ๐˜€ ๐—ฎ๐—ป๐—ฑ ๐—ฟ๐—ฒ๐—ฝ๐—ฒ๐˜๐—ถ๐˜๐—ถ๐—ผ๐—ป๐˜€ ๐—ต๐—ฎ๐—ฝ๐—ฝ๐—ฒ๐—ป.


๐—ช๐—ต๐—ฎ๐˜ ๐—ฆ๐—ต๐—ผ๐˜‚๐—น๐—ฑ ๐—ฎ๐—ป ๐—œ๐—ฑ๐—ฒ๐—บ๐—ฝ๐—ผ๐˜๐—ฒ๐—ป๐—ฐ๐˜† ๐—ฅ๐—ฒ๐—ฐ๐—ผ๐—ฟ๐—ฑ ๐—ฆ๐˜๐—ผ๐—ฟ๐—ฒ?

When a system receives an idempotent request, it needs to remember what happened.

Depending on the system, an idempotency record may contain information such as:

Idempotency Key
User ID
Request Status
Response
Created At

For example:

payment-abc123
โ†“
COMPLETED
โ†“
Previous response

When the same key arrives again, the system can return the stored result instead of processing the operation again.

๐—ง๐—ต๐—ฒ ๐—ถ๐—บ๐—ฝ๐—ผ๐—ฟ๐˜๐—ฎ๐—ป๐˜ ๐—ฝ๐—ผ๐—ถ๐—ป๐˜ ๐—ถ๐˜€ ๐˜๐—ต๐—ฎ๐˜ ๐—ถ๐—ฑ๐—ฒ๐—บ๐—ฝ๐—ผ๐˜๐—ฒ๐—ป๐—ฐ๐˜† ๐—ถ๐˜€ ๐—ป๐—ผ๐˜ ๐—ท๐˜‚๐˜€๐˜ ๐—ฎ๐—ฏ๐—ผ๐˜‚๐˜ ๐˜€๐˜๐—ผ๐—ฟ๐—ถ๐—ป๐—ด ๐—ฎ ๐—ธ๐—ฒ๐˜†โ€”๐—ถ๐˜ ๐—ถ๐˜€ ๐—ฎ๐—ฏ๐—ผ๐˜‚๐˜ ๐—ฟ๐—ฒ๐—บ๐—ฒ๐—บ๐—ฏ๐—ฒ๐—ฟ๐—ถ๐—ป๐—ด ๐˜๐—ต๐—ฒ ๐—ผ๐˜‚๐˜๐—ฐ๐—ผ๐—บ๐—ฒ ๐—ผ๐—ณ ๐˜๐—ต๐—ฒ ๐—ผ๐—ฝ๐—ฒ๐—ฟ๐—ฎ๐˜๐—ถ๐—ผ๐—ป.


๐—ช๐—ต๐—ฎ๐˜ ๐—œ๐—ณ ๐˜๐—ต๐—ฒ ๐—™๐—ถ๐—ฟ๐˜€๐˜ ๐—ฅ๐—ฒ๐—พ๐˜‚๐—ฒ๐˜€๐˜ ๐—™๐—ฎ๐—ถ๐—น๐˜€?

We also need to think about failures.

Suppose a request creates an idempotency record but the actual operation fails.

Request
โ†“
Store key
โ†“
Operation fails

Should the same key be allowed to retry?

The answer depends on the system's business rules and how the idempotency record is designed.

Some systems store the final failure and return the same result. Others allow the operation to be retried when the failure is considered safe to retry.

๐—œ๐—ฑ๐—ฒ๐—บ๐—ฝ๐—ผ๐˜๐—ฒ๐—ป๐—ฐ๐˜† ๐˜๐—ต๐—ฒ๐—ฟ๐—ฒ๐—ณ๐—ผ๐—ฟ๐—ฒ ๐—ฟ๐—ฒ๐—พ๐˜‚๐—ถ๐—ฟ๐—ฒ๐˜€ ๐—ฎ ๐—ฐ๐—น๐—ฒ๐—ฎ๐—ฟ ๐—ฑ๐—ฒ๐—ฐ๐—ถ๐˜€๐—ถ๐—ผ๐—ป ๐—ฎ๐—ฏ๐—ผ๐˜‚๐˜ ๐—ฏ๐—ผ๐˜๐—ต ๐˜€๐˜‚๐—ฐ๐—ฐ๐—ฒ๐˜€๐˜€๐—ณ๐˜‚๐—น ๐—ฎ๐—ป๐—ฑ ๐—ณ๐—ฎ๐—ถ๐—น๐—ฒ๐—ฑ ๐—ฎ๐˜๐˜๐—ฒ๐—บ๐—ฝ๐˜๐˜€.


๐—œ๐—ฑ๐—ฒ๐—บ๐—ฝ๐—ผ๐˜๐—ฒ๐—ป๐—ฐ๐˜† ๐—œ๐˜€ ๐—ฎ ๐—•๐˜‚๐˜€๐—ถ๐—ป๐—ฒ๐˜€๐˜€ ๐——๐—ฒ๐—ฐ๐—ถ๐˜€๐—ถ๐—ผ๐—ป, ๐—ก๐—ผ๐˜ ๐—๐˜‚๐˜€๐˜ ๐—ฎ ๐—ง๐—ฒ๐—ฐ๐—ต๐—ป๐—ถ๐—ฐ๐—ฎ๐—น ๐—™๐—ฒ๐—ฎ๐˜๐˜‚๐—ฟ๐—ฒ

There is no single idempotency strategy that works for every operation.

Consider:

 * Create Payment
 * Create Order
 * Send Email
 * Submit Job
 * Update Profile
Enter fullscreen mode Exit fullscreen mode

Each operation has ๐—ฑ๐—ถ๐—ณ๐—ณ๐—ฒ๐—ฟ๐—ฒ๐—ป๐˜ ๐—ฏ๐˜‚๐˜€๐—ถ๐—ป๐—ฒ๐˜€๐˜€ ๐—ฟ๐˜‚๐—น๐—ฒ๐˜€ and different consequences when repeated.

Idempotency is not simply a technology that we add to every API. ๐—œ๐˜ ๐—ถ๐˜€ ๐—ฎ ๐—ฏ๐˜‚๐˜€๐—ถ๐—ป๐—ฒ๐˜€๐˜€ ๐—ฎ๐—ป๐—ฑ ๐˜€๐˜†๐˜€๐˜๐—ฒ๐—บ-๐—ฑ๐—ฒ๐˜€๐—ถ๐—ด๐—ป ๐—ฑ๐—ฒ๐—ฐ๐—ถ๐˜€๐—ถ๐—ผ๐—ป.

Before implementing idempotency, an engineer should understand:

๐—ช๐—ต๐—ฎ๐˜ ๐—ถ๐˜€ ๐˜๐—ต๐—ฒ ๐—ผ๐—ฝ๐—ฒ๐—ฟ๐—ฎ๐˜๐—ถ๐—ผ๐—ป'๐˜€ ๐—ฏ๐˜‚๐˜€๐—ถ๐—ป๐—ฒ๐˜€๐˜€ ๐—ฒ๐—ณ๐—ณ๐—ฒ๐—ฐ๐˜, ๐—ฎ๐—ป๐—ฑ ๐˜„๐—ต๐—ฎ๐˜ ๐˜€๐—ต๐—ผ๐˜‚๐—น๐—ฑ ๐—ต๐—ฎ๐—ฝ๐—ฝ๐—ฒ๐—ป ๐—ถ๐—ณ ๐˜๐—ต๐—ฒ ๐˜€๐—ฎ๐—บ๐—ฒ ๐—ฟ๐—ฒ๐—พ๐˜‚๐—ฒ๐˜€๐˜ ๐—ฎ๐—ฟ๐—ฟ๐—ถ๐˜ƒ๐—ฒ๐˜€ ๐—ฎ๐—ด๐—ฎ๐—ถ๐—ป?

Good system design starts with that questionโ€”not with choosing a database column or library.


๐—ง๐—ต๐—ฒ ๐—•๐—ถ๐—ด๐—ด๐—ฒ๐—ฟ ๐—Ÿ๐—ฒ๐˜€๐˜€๐—ผ๐—ป

Idempotency looks like a small API feature, but it teaches a much bigger software-engineering lesson.

Distributed systems are full of uncertainty:

Requests can repeat.
Responses can disappear.
Workers can retry.
Messages can arrive again.
Multiple requests can run together.

We cannot always prevent these situations.

What we can do is design our systems so that these situations do not create incorrect results.

๐—ง๐—ต๐—ฎ๐˜'๐˜€ ๐˜๐—ต๐—ฒ ๐—ฟ๐—ฒ๐—ฎ๐—น ๐—ฝ๐˜‚๐—ฟ๐—ฝ๐—ผ๐˜€๐—ฒ ๐—ผ๐—ณ ๐—ถ๐—ฑ๐—ฒ๐—บ๐—ฝ๐—ผ๐˜๐—ฒ๐—ป๐—ฐ๐˜†: ๐—ป๐—ผ๐˜ ๐—ฝ๐—ฟ๐—ฒ๐˜ƒ๐—ฒ๐—ป๐˜๐—ถ๐—ป๐—ด ๐—ฟ๐—ฒ๐—ฝ๐—ฒ๐˜๐—ถ๐˜๐—ถ๐—ผ๐—ป, ๐—ฏ๐˜‚๐˜ ๐—บ๐—ฎ๐—ธ๐—ถ๐—ป๐—ด ๐—ฟ๐—ฒ๐—ฝ๐—ฒ๐˜๐—ถ๐˜๐—ถ๐—ผ๐—ป ๐˜€๐—ฎ๐—ณ๐—ฒ.


๐—™๐—ถ๐—ป๐—ฎ๐—น ๐—ง๐—ต๐—ผ๐˜‚๐—ด๐—ต๐˜๐˜€

Idempotency taught me an important lesson about building reliable software:

๐—ช๐—ฒ ๐—ฐ๐—ฎ๐—ป๐—ป๐—ผ๐˜ ๐—ฎ๐—น๐˜„๐—ฎ๐˜†๐˜€ ๐—ฝ๐—ฟ๐—ฒ๐˜ƒ๐—ฒ๐—ป๐˜ ๐—ณ๐—ฎ๐—ถ๐—น๐˜‚๐—ฟ๐—ฒ๐˜€, ๐—ฟ๐—ฒ๐˜๐—ฟ๐—ถ๐—ฒ๐˜€, ๐—ผ๐—ฟ ๐—ฑ๐˜‚๐—ฝ๐—น๐—ถ๐—ฐ๐—ฎ๐˜๐—ฒ ๐—ฟ๐—ฒ๐—พ๐˜‚๐—ฒ๐˜€๐˜๐˜€โ€”๐—ฏ๐˜‚๐˜ ๐˜„๐—ฒ ๐—ฐ๐—ฎ๐—ป ๐—ฑ๐—ฒ๐˜€๐—ถ๐—ด๐—ป ๐—ผ๐˜‚๐—ฟ ๐˜€๐˜†๐˜€๐˜๐—ฒ๐—บ๐˜€ ๐˜๐—ผ ๐—ต๐—ฎ๐—ป๐—ฑ๐—น๐—ฒ ๐˜๐—ต๐—ฒ๐—บ ๐˜€๐—ฎ๐—ณ๐—ฒ๐—น๐˜†.

The next time you design an API, background job, payment flow, or distributed service, ask one simple question:

"๐—ช๐—ต๐—ฎ๐˜ ๐—ต๐—ฎ๐—ฝ๐—ฝ๐—ฒ๐—ป๐˜€ ๐—ถ๐—ณ ๐˜๐—ต๐—ถ๐˜€ ๐—ผ๐—ฝ๐—ฒ๐—ฟ๐—ฎ๐˜๐—ถ๐—ผ๐—ป ๐—ฟ๐˜‚๐—ป๐˜€ ๐—ฎ๐—ด๐—ฎ๐—ถ๐—ป?"

That question can reveal problems that are easy to miss during normal development.

Thanks for reading! ๐Ÿ™Œ

I hope this article helped make idempotency easier to understand, especially if you're learning distributed systems or building production-level applications.

If you found it useful, feel free to share it with another developer who might benefit from it.

Keep building. Keep learning. Keep questioning how your systems behave when things go wrong. ๐Ÿš€

๐—”๐—ฏ๐—ผ๐˜‚๐˜ ๐˜๐—ต๐—ฒ ๐—”๐˜‚๐˜๐—ต๐—ผ๐—ฟ

I'm a software engineer interested in building reliable software systems and continuously improving my understanding of system design, distributed systems, and backend engineering.

This article was written while exploring these concepts through hands-on project development and practical engineering problems.

Top comments (0)