Recuro.

Idempotency

Idempotency means that running an operation once produces the same result as running it multiple times. If you send the same request twice and the outcome is identical — no duplicate side effects, no extra records, no double charges — the operation is idempotent.

Why it matters for background jobs

Background jobs fail. Networks drop, servers restart, timeouts happen. When a job fails, you retry it. But here's the problem: did the job actually fail, or did it succeed and only the acknowledgment was lost?

If your job isn't idempotent, retrying it can cause real damage: duplicate emails sent to customers, double charges on credit cards, or corrupted data from applying the same transformation twice. Idempotency is what makes retries safe.

Idempotent vs non-idempotent operations

Operation Idempotent? Why
Set user status to "active"YesSame result no matter how many times you run it
Delete record by IDYesFirst call deletes it, subsequent calls are no-ops
Upsert a row by unique keyYesCreates or updates — same final state either way
Send a welcome emailNoEach call sends another email
Increment a counterNoEach call changes the value
Charge a credit cardNoEach call creates a new charge

How to make a job idempotent

Idempotency keys

Assign a unique key to each job (usually a UUID or a hash of the job's parameters). Before processing, check if a job with that key has already been completed. If it has, skip it. Most payment APIs (Stripe, PayPal) accept an idempotency key header for exactly this reason.

Database upserts

Use INSERT ... ON CONFLICT UPDATE (or your ORM's equivalent) instead of plain inserts. This way, running the job twice writes the same row rather than creating a duplicate.

Deduplication logic

Before performing a side effect (sending an email, calling an API), check if it's already been done. Store a record of completed actions and skip any that already exist.

What happens when you get it wrong

FAQ

What is an idempotency key?

An idempotency key is a unique identifier attached to a request so the server can recognize duplicates. If two requests arrive with the same key, the server processes only the first and returns the cached result for the second. It's the standard pattern for making non-idempotent operations (like payments) safe to retry.

Are GET requests always idempotent?

By design, yes. HTTP GET is defined as a safe, idempotent method — it should only read data, never modify it. In practice, some poorly designed APIs use GET for mutations, but that violates the HTTP specification.

How do I implement idempotency in my API?

Accept an idempotency key in the request header (e.g., Idempotency-Key). Before processing, check if you've already handled a request with that key. If yes, return the stored response. If no, process the request and store the result keyed by that ID.

Idempotency is essential when handling webhooks (which may be delivered more than once) and when retrying failed jobs with exponential backoff. Job queues rely on idempotent operations to retry safely without causing side effects.

Stop managing infrastructure. Start scheduling jobs.

Recuro handles cron scheduling, retries, alerts, and execution logs -- so you can focus on building your product.

No credit card required