Skip to content

Long-running operations: 202 Accepted plus a status resource

Accept, record, point: the reply says where to ask, and the record outlives every process that touched it.

Predict first

Before you read: predict

A payments ledger's month-end export takes 240 s of work. Each design below is hit by the same API deploy 90 s after the POST: new requests go to the new API process, and the old process closes whatever is still open 30 s later. The export workers run as their own deployment and are not restarted. A 202 reply carries a Retry-After of 25 s; a client stops polling at a 404, and no client ever sends the POST twice.

Which design leaves the client holding the export file?

Pick one

The 30-second version

Work that outlives a request's deadline is not done inside the request. The API records an operation, hands the work to a queue and answers 202 with a Location. The client polls that resource, waiting each Retry-After, until it reads succeeded or failed. The record lives in the database, so any process, and any client, can answer.

Accept, record, point: the reply says where to ask, and the record outlives every process that touched it.

How it works

Step 1 of 14

Every hop has a deadline. Clients, proxies and balancers time out; a deploy closes what its old process still holds after a short drain. Azure

Analogy: A seed-testing laboratory

A grower hands in a seed sample for a germination test that takes days. The front desk writes it into the bound register and gives back a receipt with the sample number and the line to ring; the grower goes home. Ringing reads the register: received, on the germination bench, certificate issued with where to collect it, or test void with the reason. The desk says "ring again on Thursday".

In the lab In the API
receipt with sample number and phone line 202 with Location (step 4)
the bound register, not the bench whiteboard the database record (steps 5–6)
received, on the bench, certificate, void with reason pending, running, succeeded, failed with error (step 7)
a call that went through, whatever the register says a 200 whose body carries the record's status (step 8)
"ring again on Thursday" Retry-After (step 10)

In real terms: the reply points at a record; the record, not the connection, carries the outcome.

Breaks down when: a grower can see the bench through the window, while a client sees only what the record says. A grower who waits in the lobby is sent out when the lab closes for the night, with no receipt to ask about.

Contrasting case: a soil pH strip read at the desk in a minute: short work answered inside the request, well within every deadline.

Examples, run for real

4.1 ExamHall: the results export

EXH-3660: POST /exams/econ-201/exports built the 240 s CSV inside the request, with timeouts raised to cover it; a deploy 60 s in cut it. MR !3960 answers 202 with Location: /operations/op_1, writes the row to the database and queues the job for the export workers.

4.1 EXH-3660 POST /exams/econ-201/exports holds the export (240 s) · deploy at 60 s · requests cut 1 · file no · exports finished 0 · client ends: cut (UND_ERR_SOCKET)
4.1 MR !3960 202 + Location /operations/op_1, row in the database · same deploy · requests cut 0 · file yes · exports finished 1 · client ends: succeeded at t=270
4.1 MR !3960 statuses the poller read: running x8, succeeded

The deploy ended the held request (steps 1–2); the poller kept asking the new process, which read the same row (step 5).

4.2 Payments ledger: a statement run, polled

A ledger API queues a statement run while its workers are busy: one takes it only at t=40 and finishes it at t=100. Every reply says Retry-After: 30.

4.2 statement run: worker takes it at t=40, done at t=100 · Retry-After 30 · GETs 4 · read pending, running, running, succeeded

The poller read what the record held at each GET it was told to make (steps 10–11), and it stopped on the terminal status (step 12).

Try it

Answer first, then check. Nothing is saved.

Question 1 of 7

A ledger API answers POST /statements with 202, a Location and Retry-After: 20, and its status replies carry Retry-After: 20 until the run ends. A worker takes the job at t=5 and finishes it at t=55. The client waits each reply's Retry-After before its next GET.

Which statuses do its GETs read, in order?

Pick one

Question 2 of 7

A reconciliation export fails at t=30; the worker records "storage refused the upload". The client polls every 20 s through the team's HTTP client, which retries a 5xx after 10 s, at most 3 times, and ends the call on a 4xx. On-call is paged once the API has served 3 5xx replies.

Which reply to GET /operations/{id} for that operation lets the screen show what happened to the export, and why, without paging anyone?

Pick one

Question 3 of 7

A finance analyst starts a quarter-end reconciliation report from her browser tab, which polls every 15 s; the report finishes at t=40. A finance dashboard asks for the same operation at t=50, and at t=60 the analyst reloads her tab, which reads its operation URL, if it has one, from its address bar.

Which design lets both the dashboard and the reloaded tab show the report's link?

Pick one

Question 4 of 7

A ledger export's first run stops at t=30: the ledger snapshot was locked, and any later run takes 100 s after a worker picks it up. Status replies carry Retry-After: 20.

Which client loop ends with the export file?

Pick one

Question 5 of 7

Your lead wants to fix the results export by raising the load balancer and server timeouts to ten minutes.

Write three sentences to the lead on why that is not enough and what the export endpoint should return instead.

Question 6 of 7

A ledger API runs two API instances behind a round-robin balancer, and a worker fleet builds the files. Its async design keeps each operation's status in a shared cache, whose entries expire 60 s after they were last written. A worker writes running when it takes the job at t=5 and succeeded when the export ends at t=150. Status replies carry Retry-After: 20, and the client stops on a 404.

Which change gets the client its file with one export run?

Pick one

Question 7 of 7

A ledger API's status monitor meets two incidents. (1) An export fails at t=30. (2) The operations table is unreachable from t=20 to t=45, and that export succeeds at t=60. The client polls every 20 s through the team's HTTP client, which retries a 5xx after 10 s, at most 3 times; on-call is paged once the API has served 3 5xx replies.

Which pair of monitor replies shows the export in (1) as failed, with its reason, delivers the file in (2), and pages on-call for the outage and for nothing else?

Pick one

Go deeper

Pro tip
  1. Rehearse a deploy against a long request before shipping one. Start the slowest operation through the real balancer, restart the API with the same drain the pipeline uses, and check whether the client got its result, then whether it can find it by URL. When: any endpoint whose work can outlast the drain (steps 1–6). Verify.
Sources
  • RFC 9110 §15.3.3, 202 Accepted: https://www.rfc-editor.org/rfc/rfc9110.txt · rfc9110.txt. Named in the curriculum row. "the request has been accepted for processing, but the processing has not been completed"; "without requiring that the user agent's connection to the server persist until the process is completed"; "The representation sent with this response ought to describe the request's current status and point to (or embed) a status monitor". Supports steps 4, 7. Valid as of 2026-10-12.
  • Microsoft Azure REST API Guidelines, Long-Running Operations & Jobs: https://github.com/microsoft/api-guidelines/blob/vNext/azure/Guidelines.md · ms-azure-guidelines.md. The row names "Microsoft REST API Guidelines: long-running operations". "due to services not wanting to maintain long-lived connections (>1 seconds) and load-balancer timeouts, the operation must execute asynchronously"; the status monitor's status enum "NotStarted", "Running", "Succeeded", "Failed", and "Canceled", with error "If status=="Failed""; "DO support the GET method on the status monitor endpoint that returns a 200-OK response with the current state of the status monitor"; "DO include a retry-after header in the response if the operation is not complete … an integer number of seconds that the client should wait before polling"; "DO retain the status monitor resource for some publicly documented period of time (at least 24 hours) after the operation completes"; LROs "may be polled … by the same client, another client, or even multiple clients/browsers". Azure names the header operation-location; this lesson uses Location, as the Graph pattern below does; RFC 9110 asks only that the 202's body point to a status monitor. Supports steps 1, 7–8, 10, 13. Valid as of 2026-10-12.
  • Microsoft Graph API design pattern, Long running operations: https://github.com/microsoft/api-guidelines/blob/vNext/graph/patterns/long-running-operations.md · ms-graph-lro.md. "For the LRO pattern, you should return the Location header that indicates the location of a new stepwise operation resource"; "A recommended minimum retention time for a stepwise operation is 24 hours". Supports steps 4, 13. Valid as of 2026-10-12.
  • ms-legacy-guidelines.md (the older Microsoft guidelines, master branch) was fetched as background and keys nothing.

Checked against the tools and docs as of 2026-10-12.