Idempotency Keys in Distributed Job Systems

One of the most overlooked reliability problems in distributed systems is duplicate requests.

A user clicks a button twice. A mobile client retries after a timeout. A load balancer retransmits a request. An API gateway retries after a transient network failure.

Without protection, these duplicate requests can produce duplicate side effects:

  • Two welcome emails
  • Two invoices
  • Two payment attempts
  • Two image processing jobs
  • Two webhook deliveries

Codily addresses this problem using idempotency keys on its POST /jobs endpoint. Rather than creating multiple jobs for the same logical operation, the system recognizes repeated submissions and safely returns the original job.

This article explains why idempotency matters and how it improves reliability in asynchronous architectures.


What Is Idempotency?

An operation is idempotent if performing it multiple times has the same effect as performing it once.

For example:

Create Job (first request)
        │
        ▼
Job Created

Create Job (same request again)
        │
        ▼
Return Existing Job

No duplicate processing occurs.

This differs from ordinary POST semantics, where every request typically creates a new resource.


Why Async Systems Need It

Background job systems intentionally decouple request submission from execution.

A client sends a request:

Client
   │
   ▼
POST /jobs
   │
   ▼
Queue
   │
   ▼
Worker

Now imagine the client loses its network connection before receiving the response.

From the client's perspective, it's impossible to know whether:

  • The server never received the request.
  • The server created the job successfully.
  • The response was lost after processing.

The safest client behavior is usually to retry.

Without idempotency, that retry creates another identical job.


The Idempotency-Key Header

Codily solves this by allowing callers to attach an Idempotency-Key header to job submissions.

Example:

POST /jobs
Idempotency-Key: order-42-email

The key identifies the logical operation rather than the HTTP request itself.

If the same client retries with the same key, Codily recognizes that the operation has already been accepted.


Deduplication Logic

Internally, the workflow is straightforward.

Incoming Request
        │
        ▼
Read Idempotency-Key
        │
        ▼
Lookup Existing Job
        │
 ┌──────┴────────┐
 │               │
Found         Not Found
 │               │
 ▼               ▼
Return      Create New
Existing       Job

The lookup typically uses a unique identifier scoped to the tenant, ensuring that two different organizations can safely reuse the same key without conflict.


A Simplified Database Model

A representative schema might include:

CREATE TABLE jobs (
    id UUID PRIMARY KEY,
    tenant_id TEXT NOT NULL,
    idempotency_key TEXT,
    status TEXT NOT NULL
);

To guarantee uniqueness within a tenant:

CREATE UNIQUE INDEX idx_jobs_tenant_idempotency
ON jobs (
    tenant_id,
    idempotency_key
);

This ensures that repeated submissions for the same logical operation resolve to a single job record.


What Happens on Duplicate Submission?

Suppose the first request succeeds:

POST /jobs
Key: invoice-501
        │
        ▼
Job Created
        │
        ▼
Job ID:
abc123

Later, the client retries with the same key:

POST /jobs
Key: invoice-501
        │
        ▼
Existing Job Found
        │
        ▼
Return Job ID:
abc123

No second job is inserted into the queue.

From the client's perspective, the retry succeeds while preserving exactly one logical operation.


Why This Matters in Practice

Preventing Duplicate Emails

Imagine a password reset workflow.

Without idempotency:

Retry
   │
   ▼
Two Email Jobs
   │
   ▼
User Receives
Two Emails

With idempotency:

Retry
   │
   ▼
Existing Job Returned
   │
   ▼
One Email Sent

The user experience remains consistent even if the client retries multiple times.


Preventing Duplicate Invoice Generation

Generating invoices often triggers downstream effects such as PDF creation, notifications, and accounting updates.

Creating two jobs accidentally could lead to duplicate records and reconciliation problems.

An idempotency key tied to the invoice identifier ensures that retries reuse the original job rather than generating another.


Preventing Duplicate Webhooks

Webhook producers commonly retry failed deliveries.

Without deduplication, downstream systems may process the same business event repeatedly.

Associating an idempotency key with each event lets consumers recognize retransmissions and avoid duplicate side effects.


Client Retries Become Safe

Many HTTP libraries automatically retry transient failures.

For example:

Request
   │
Timeout
   │
Retry
   │
Retry
   │
Retry

When each retry carries the same idempotency key, the server can safely return the original job rather than enqueueing multiple copies.

This transforms unreliable networks from a correctness problem into a simple availability concern.


Relationship to At-Least-Once Delivery

Distributed queues frequently provide at-least-once delivery, meaning a message may be processed more than once.

Idempotency complements this model.

Even if:

  • the client retries,
  • the queue redelivers,
  • or the worker restarts after a crash,

the logical operation remains consistent because duplicate requests resolve to the same underlying work item or are processed safely.


Choosing Good Idempotency Keys

Keys should represent the business operation rather than a random retry attempt.

Examples:

order-982-confirmation-email

payment-50021

invoice-2026-00045

user-123-password-reset

Poor choices include timestamps or randomly generated values that change with every retry, since those defeat deduplication entirely.


Handling Expiration

Some systems retain idempotency keys indefinitely, while others expire them after a configurable period.

Retention policies depend on business requirements:

  • Payment operations may require long-lived guarantees.
  • Temporary background jobs may only need protection for several days.
  • Event replay systems may archive historical mappings separately.

The key principle is that retries occurring within the expected retry window should resolve to the original operation.


Designing Idempotent Workers

Submission deduplication is only part of the story.

Workers should also be written to tolerate repeated execution where practical.

For example:

INSERT INTO emails (
    message_id,
    recipient
)
VALUES ($1, $2)
ON CONFLICT (message_id)
DO NOTHING;

Using deterministic identifiers or conflict-aware writes prevents duplicate side effects if a task is replayed.


Final Thoughts

Retries are an unavoidable part of distributed systems. Networks fail, clients disconnect, and intermediaries resend requests. Without safeguards, those retries can produce duplicate jobs and unintended side effects.

Codily's Idempotency-Key support on POST /jobs provides a simple but powerful solution: identify the logical operation, deduplicate repeated submissions, and return the original job instead of creating a new one. Whether the task is sending an email, generating an invoice, or processing a webhook, idempotency transforms retries from a source of inconsistency into a safe and expected part of the system's reliability strategy.