How do you handle long-running operations in a REST API?
Learn the async 202 Accepted pattern for long-running REST API operations: job resources, status endpoints, polling vs webhooks, queues, and retries.
Expected Interview Answer
Handle long-running operations asynchronously: accept the request, return 202 Accepted with a status URL, do the work in the background, and let the client poll or receive a webhook when it finishes.
Instead of blocking the HTTP connection until a slow job (report generation, video encoding, bulk import) completes, the server creates a job resource, returns its id and a Location header pointing to a status endpoint, and processes it via a queue or worker. The client polls GET /jobs/{id} for state (pending, running, succeeded, failed) or is notified via a webhook/SSE, then fetches the result from a separate resource URL. This keeps requests fast, avoids gateway timeouts, and makes the work retryable and observable.
- Avoids client and gateway timeouts
- Frees server connections and threads
- Makes work retryable and idempotent
- Gives clients visible progress and status
- Scales via queues and background workers
AI Mentor Explanation
It is like a third-umpire review: the on-field umpire does not freeze the whole match while the decision is checked. Play pauses with a signal (your 202 Accepted), the review runs off to the side, and only when the verdict is ready is it relayed back to the ground so the game continues without the field crew standing idle.
Step-by-Step Explanation
Step 1
Accept and acknowledge
Validate the request, create a job resource, and immediately return 202 Accepted with the job id and a Location header pointing to its status URL.
Step 2
Queue the work
Push the task onto a message queue so a background worker processes it independently of the HTTP request lifecycle.
Step 3
Track state
Persist job status (pending, running, succeeded, failed) plus progress and error details so it can be queried at any time.
Step 4
Expose a status endpoint
Provide GET /jobs/{id} returning current state, and once complete a link to the result resource.
Step 5
Notify or let clients poll
Support polling with backoff, or push completion via webhook or Server-Sent Events to avoid constant polling.
Step 6
Return the result
Store the output as its own resource and let the client fetch it, keeping status and payload cleanly separated.
What Interviewer Expects
- Knowledge of the 202 Accepted async pattern
- Understanding of queues and background workers
- A job/status resource model with a status URL
- Polling with backoff versus webhooks/SSE trade-offs
- Handling timeouts, retries, and idempotency
Common Mistakes
- Blocking the request until the job finishes, risking gateway timeouts
- Returning 200 instead of 202 for accepted-but-incomplete work
- No way to check job status or fetch the result
- Aggressive fixed-interval polling with no backoff
- Ignoring idempotency so retries duplicate the job
Best Answer (HR Friendly)
“For slow tasks, the API says 'got it, working on it' right away and gives the caller a ticket number instead of making them wait. The work happens in the background, and the caller checks the ticket or gets a notification when the result is ready.”
Code Example
app.post('/reports', async (req, res) => {
const job = await jobs.create({ status: 'pending', params: req.body })
queue.enqueue('generate-report', { jobId: job.id })
res.status(202)
.location(`/jobs/${job.id}`)
.json({ id: job.id, status: 'pending' })
})
app.get('/jobs/:id', async (req, res) => {
const job = await jobs.find(req.params.id)
if (!job) return res.sendStatus(404)
const body = { id: job.id, status: job.status }
if (job.status === 'succeeded') body.result = `/reports/${job.id}`
res.json(body)
})Follow-up Questions
- When would you choose webhooks over polling for completion?
- How do you make job submission idempotent?
- How do you communicate progress percentage to clients?
- What status code and headers does the async pattern use?
- How do you handle a job that fails partway through?
MCQ Practice
1. Which HTTP status best signals a long-running request was accepted but not yet complete?
202 Accepted means the request was accepted for processing but has not finished; a Location header typically points to a status resource.
2. What is the main advantage of webhooks over polling for job completion?
Webhooks push a notification when the job finishes, eliminating the wasted requests and latency of repeated polling.
3. Why keep the job status and the job result as separate resources?
Status checks stay small and fast, while the possibly large result is fetched only once, from its own URL, when ready.
Flash Cards
What status code starts an async operation? — 202 Accepted, usually with a Location header pointing to a job status URL.
How do clients learn a job finished? — By polling the status endpoint (with backoff) or receiving a webhook / SSE push.
Why use a queue? — It decouples request handling from processing, enabling background workers, retries, and scaling.
Why separate status and result resources? — Status stays lightweight for frequent checks; the large result is fetched once from its own URL.