Skip to content
Articles
TechnicalInfrastructureProduction

Queues, Retries, and Idempotency for Reliable AI Jobs

How to survive duplicate clicks, worker crashes, provider timeouts, output-copy failures, billing uncertainty, and at-least-once delivery.

Published Jul 17, 2026Updated Jul 23, 202616 min readDifficulty: Advanced4/5
In this article
Timeline diagram showing an AI job moving through acceptance, queueing, timeout, retry, and one durable completion
A reliable system separates one user intent from the attempts made to complete it. Idempotency prevents duplicate jobs while retries recover eligible attempts.

The Short Answer

Expensive AI work must assume that requests time out, workers disappear, networks split, and users click twice. Reliability comes from giving every user intent a stable identity, recording every attempt, and making side effects safe to reconcile.

The most dangerous moment

A client times out after the server accepted the request. The client cannot tell whether nothing happened or a costly generation is already running. Retrying with a new identity can create a second job and a second charge.

One Logical Job Can Have Several Attempts

A logical job represents what the user asked to create. An attempt represents one execution on one worker or provider. Keep those identifiers separate.

job_456
  intent: render scene 7, take 2
  state: running
  idempotency_key: create-scene-7-take-2

attempt_1
  server: sage3
  provider_prompt_id: abc
  state: timed_out

attempt_2
  server: sage2
  state: running

This distinction answers important questions. Did the user create one job or two? Which server performed the work? Has cost already been reserved? Does a provider prompt ID exist that can be checked before retrying?

Idempotency Protects The Create Boundary

An idempotency key names one mutation. The client sends the same key when retrying the same request. The server either returns the original result or rejects mismatched parameters instead of creating another job.

Create(key, payload) = job456
Create(key, same payload) = job456
Create(key, different payload) = conflict
Desired create-job behavior.

Stripe’s API is a useful public reference: it stores the first result for an idempotency key and returns that result for matching retries. It also compares parameters to prevent accidental reuse. The same principle applies to generation creation even when payments are not involved.

Keys should not contain sensitive prompts or personal data. A random identifier or stable client operation ID is enough. Scope keys to the authenticated owner so two users cannot collide.

Retries Need A Failure Policy

FailureTypical policyReason
Invalid dimensionsDo not retryPermanent until input changes
Queue unavailableBounded backoffLikely transient infrastructure failure
GPU OOMRetry with changed placementSame server may fail again
Provider timeout after submitReconcile firstOriginal work may still be running
Output copy failureRetry copyDo not regenerate completed pixels

Backoff reduces synchronized retry storms. A common shape doubles the delay and adds jitter:

delayn = min(cap, base × 2n) + random(0, jitter)
Bounded exponential backoff with jitter.

Leases And Heartbeats Detect Lost Workers

A queue handing a job to a worker does not prove the worker will finish. A lease marks temporary ownership. The worker renews it with heartbeats. If the lease expires, a recovery process can inspect provider state and decide whether to requeue.

Lease expiry is evidence that the worker stopped reporting, not evidence that external work stopped. ComfyUI or a cloud provider may still be generating. Store the provider prompt ID before waiting so recovery can query history.

Exactly-Once Execution Is The Wrong Goal

A worker can complete generation and crash before acknowledging the queue. The queue may then deliver the job again. Preventing every duplicate execution across all failures is difficult. Preventing duplicate user-visible effects is tractable.

  • Use a unique constraint on the idempotency scope and key.
  • Use conditional state transitions, such as running to completed only once.
  • Store output identity and hash before publishing completion.
  • Make cost settlement compare-and-set or transactionally guarded.
  • Deduplicate progress events by job, attempt, and sequence number.
  • Reconcile provider history before launching another expensive attempt.

Billing And Output Ownership Must Follow State

Reserve cost before execution if overspending must be prevented. Settle actual usage only once. Release or refund reservations on terminal failure according to a documented policy.

Outputs need the same discipline. A completed provider file should be copied into durable application storage and attached to the logical job. A copy retry should target that file. Regenerating creates a new stochastic result and may charge twice.

A Minimal State Machine

queued -> running -> completed
   |         |
   |         +-> retry_wait -> queued
   |         +-> reconciling -> running | completed | failed
   +-> cancelled
   +-> failed

Rules:
- terminal transitions are conditional
- attempts are append-only records
- completion owns one durable output
- settlement happens once

State changes should be logged with safe identifiers and reasons. The log should explain why a retry happened without leaking the user’s private prompt or media URL.

Frequently Asked Questions

What is the difference between a retry and a duplicate job?

A retry is another attempt to complete the same logical job. A duplicate is a second logical job created from the same user intent. Idempotency keys prevent accidental duplicates; attempt records describe retries.

Can a queue guarantee exactly-once execution?

Distributed queues normally provide at-least-once or at-most-once delivery properties. Exactly-once user-visible effects are built with idempotent operations, durable state, deduplication, leases, and reconciliation.

When should an AI generation be retried automatically?

Retry transient failures with bounded backoff when the previous attempt is known not to have completed. Validate permanent input errors immediately and reconcile indeterminate provider timeouts before generating again.

Sources

Primary queue and API reliability documentation used for the retry and idempotency model.

Keep reading

Related articles

All guides
Diagram tracing an AI generation job from browser to API, queue, GPU worker, storage, and progress channel
TechnicalInfrastructure

From Click to Clip: Inside an AI Generation Job

Follow an AI generation request through validation, durable job state, Redis-backed queues, ComfyUI execution, WebSocket progress, output storage, and failure recovery.

15 min readDifficulty 2/5
Diagram showing GPU progress flowing through an event bus and API WebSocket to a browser progress bar
TechnicalInfrastructure

How Live AI Progress Reaches the Browser

Trace GPU progress events through workers and APIs to the browser, compare WebSockets, SSE, and polling, and design secure reconnect and fallback behavior.

14 min readDifficulty 3/5
Queues, Retries, and Idempotency for Reliable AI Jobs | Movey