AI Provider Outage Playbook
How to define triggers, degradation paths, communication, and post-incident review when an upstream model or provider becomes unstable.
Read articleA practical design for image-generation queues, bounded retries, uncertain provider outcomes, and spending controls that survive worker failures.

An image generator can look healthy while its queue quietly becomes impossible to drain. Requests still receive acknowledgments, workers still produce images, and the dashboard still shows activity. Meanwhile, customers wait beyond useful deadlines and retries consume the money intended for new work. Successful requests are not enough to demonstrate a sustainable service.
Consider a hypothetical catalog studio where merchants request product backgrounds. Interactive previews compete with overnight exports, and both use a provider with finite capacity. The following design is an engineering proposal, not a description of XVAPI internals. Its objective is to preserve useful work while making delay, duplicate execution, and financial exposure explicit.
Separate accepting a job from starting generation. At admission, authenticate the caller, validate parameters, check reference-asset ownership, establish a deadline, and reserve a bounded spending allowance. Persist the accepted specification before acknowledging it. A queue message should identify durable work, not be the only place that work exists.
An admission idempotency key should be scoped to the tenant and operation. Associate it with a fingerprint of the normalized request. Reusing a key with different dimensions, prompts, or output counts should produce a conflict rather than silently returning an unrelated job. Document key retention because deduplication ends when that record expires.
Writing a database row and publishing a message are separate failure opportunities. A transactional outbox can record the job and its pending dispatch together; a publisher subsequently delivers the message. This adds maintenance and cleanup work, but avoids acknowledging a job that never reaches a worker. Assume duplicate message delivery and make claims conditional.
A queue-length limit alone treats a thumbnail and a large multi-image export as equal. Track estimated work alongside item count, using dimensions, image count, and requested processing stages. Estimates will be imperfect; their purpose is admission control, not precise billing. Revisit them when models or request shapes change.
Give interactive and batch work separate scheduling classes while enforcing a shared provider ceiling. Weighted fair scheduling can prevent one large merchant from monopolizing workers. Strict interactive priority is simpler, but may starve exports indefinitely. Reserve some service for batch work or explicitly advertise that it is best effort.
Deadlines should include queue residence, execution, and required delivery processing. Expire work before dispatch if its useful window has closed. Avoid promising exact completion times when provider duration is unpredictable. Report queue age and progress honestly, and offer cancellation rather than an indefinitely animated waiting screen.
In the catalog studio, a preview no longer matters after the editor replaces its prompt. Marking that job obsolete before dispatch saves capacity without disrupting the replacement. Once execution starts, however, cancellation may only stop downstream delivery; it cannot guarantee that a provider stops processing or charging.
Workers need a bounded claim on a job so abandoned work can be recovered. A claim might contain a lease expiry and a monotonically increasing generation number. Heartbeats extend ownership, while conditional updates prevent an older worker from overwriting a newer worker's result. This protects local state from stale writers.
It does not prevent duplicate external execution. Suppose a worker submits generation, loses connectivity, and stops renewing its lease. Another worker acquires the job while the first provider request continues. Dispatching again immediately may create two chargeable generations. Store an attempt record before submission and distinguish an abandoned worker from a confirmed failed provider operation.
Where supported, persist a provider operation identifier and reconcile its status. Provider idempotency can help only within its documented scope and retention window. If neither facility exists, choose a deliberate policy for ambiguous outcomes: pause for investigation, wait through a reconciliation interval, or retry under a separately approved duplicate-cost allowance.
Classify failures before scheduling another attempt. Invalid dimensions require corrected input. An authentication failure requires credential repair. A policy rejection should not trigger provider hopping to evade enforcement. Rate limiting calls for pacing, while some transport failures and temporary server errors may justify another attempt.
RFC 9110 HTTP Semantics explains idempotent methods and the restrictions around automatically retrying non-idempotent requests. A generation request using POST does not become safe to repeat because the connection timed out. The server may already have accepted it, and a missing response is not proof of non-execution.
Choose one layer to own retries. Otherwise an SDK, gateway, and worker can each multiply attempts. Use capped exponential backoff with jitter, honor applicable Retry-After guidance, and check the remaining deadline before sleeping. A shared retry budget limits recovery traffic across jobs; a per-job attempt limit alone does not protect an overloaded provider.
The Amazon Builders' Library discussion of timeouts, retries, and backoff with jitter is useful background for these choices. Backoff distributes demand; it does not create capacity. When the queue is already missing deadlines, rejecting new low-priority work can be more effective than extending retry schedules.
Treat spending authorization as a reservation ledger rather than a balance read followed by an unrelated update. Concurrent admissions must not each spend the same available funds. Reserve atomically against a tenant allowance and record which job owns the reservation. Release, settlement, and adjustment operations also need idempotent identifiers.
A job allowance should account for authorized output count, eligible provider prices, and permitted retries. In the studio example, requesting several backgrounds does not automatically authorize regenerating the entire batch after one image fails. Track successful outputs individually and retry only missing work when the provider contract supports that distinction.
Keep estimated exposure separate from settled cost. A timeout may leave a charge unresolved, so releasing every reservation immediately can understate liability. Hold an uncertainty amount until reconciliation or a documented expiry policy resolves it. That policy trades available customer budget against the risk of late charges and needs a clear owner.
A local spending ceiling is not an absolute upstream invoice guarantee when charges arrive late or pricing is variable. Reduce exposure with conservative estimates, dispatch caps, and provider-side limits where available. If the maximum authorized cost cannot be bounded, require explicit approval or reject the request instead of describing an estimate as a hard cap.
Imagine a merchant requests a set of catalog backgrounds. Admission stores the normalized specification, deadline, and spending reservation. The outbox publishes a job identifier. A worker claims it, records an attempt, and submits the request. The provider accepts, but the connection drops before its response reaches the worker.
The job now has an unknown execution outcome, not an ordinary retryable failure. A reconciler queries the provider when supported. If it finds completed output, the system validates and stores that output before marking delivery ready. If it confirms rejection before execution, the scheduler may retry within the original deadline and allowance.
If the outcome remains unknowable, the product exposes a pending investigation state or a clearly priced retry choice. That is less convenient than automatic resubmission, but it preserves an honest contract. Successful delivery, provider execution, and financial settlement can finish at different times; forcing them into one boolean hides operational obligations.
Watch oldest eligible queue age, expired jobs, running claims, unknown outcomes, retry volume, and unsettled exposure. Break these down by workload class and provider where useful. Avoid tenant identifiers as unbounded metric labels; detailed tenant investigation belongs in access-controlled records. Low average latency can coexist with a badly starved batch queue.
Rehearse failures at boundaries: after reservation but before publication, after submission but before acknowledgment, and after output storage but before completion. Verify recovery without creating extra provider calls or losing accounting records. Inject stale-worker updates to prove conditional writes actually reject them. A clean happy-path load test will not establish these properties.
The goal is not a queue that accepts everything. It is a service that knows which work it has promised, how much uncertainty it can afford, and when another attempt would make the situation worse.