idempotence and retry
/ idempotence: "eye-dem-POH-tens" /
Imagine pressing the 'call lift' button. Pressing it once summons the lift; pressing it five more times changes nothing - the lift is already coming. That button is idempotent: doing it again has the same effect as doing it once. Now imagine a 'withdraw 100 dollars' button instead. Pressing that five times takes 500 dollars. That one is not idempotent, and the difference becomes critical the moment you want to retry after a failure.
Idempotence is the property that performing an operation more than once has the same effect as performing it exactly once. Setting a value (x = 5) is idempotent; incrementing one (x = x + 1) is not. Deleting a file 'if it exists' is idempotent; appending a line is not. Retry is the strategy of automatically trying a failed operation again - useful because many failures are transient: a network packet was dropped, a server was briefly overloaded, a lock was momentarily held. A short pause and another attempt often just works (often with backoff - waiting longer between successive attempts to avoid hammering a struggling system). The two ideas are inseparable because retry is only safe when the operation is idempotent. If you send a 'charge the card' request, get no response, and retry, you might charge the customer twice - the first request may actually have succeeded and only its reply was lost. Idempotence is what makes retry safe: if the operation is idempotent, a duplicate retry does no extra harm.
Why it matters: retry is one of the cheapest, most effective robustness tools for transient failures, but it is a loaded gun if the operation has side effects that stack up. This is why distributed systems work so hard to make operations idempotent - for example, by attaching a unique request id so the server can recognise and ignore a duplicate ('I already processed request 7'), turning a non-idempotent action into a safely-retryable one. The honest caveats: not every failure should be retried - a 'file not found' or 'permission denied' will fail identically every time, so retrying just wastes effort; and naive retry without a limit and without backoff can turn a brief hiccup into a self-inflicted overload (a retry storm) that keeps a struggling system down.
Idempotent and safe to retry: open(path, O_CREAT) followed by writing the full file content - rerunning it lands the same file. Not idempotent: a bare write() that appends a log line - retrying after a lost response can write the line twice. The fix is often a unique id the receiver dedupes on.
Retry is safe exactly when redoing the operation cannot pile up extra side effects.
Retry is only safe for idempotent operations; retrying a non-idempotent one (a charge, an append) can duplicate its effect when an earlier attempt actually succeeded but its reply was lost. Also bound retries and back off, or a transient blip becomes a self-inflicted retry storm.