ON THIS PAGE (7 SECTIONS)
- ✓Platforms close idle requests. A task that must finish anyway cannot depend on the connection staying open.
- ✓The request records an intent and a status. The worker performs the side effect and can retry it safely.
- ✓The user needs a way to see pending, done, and failed. A spinner until the socket dies is not a status.
- ✓A model call is often this shape: too slow and too uncertain for the request thread.
The handler validates the form, generates a PDF, uploads it, emails three people, and then writes the database row. The proxy closes the connection at its deadline. The email went out. The row did not. The user retries. More email goes out. The request was doing five jobs, and it could not finish them as one.
A request is good at a short, transactional decision: is this caller allowed, is this payload valid, can we record the intent. It is a poor place for work that waits on other systems, that must happen even if the browser leaves, or that you may need to run again without the user. Put that work in a job. Return an id and a status. Let the client poll or receive a later notice.
What stays in the request
- Authentication and authorization.
- Validation of the payload. Reject it before you enqueue it.
- A durable record of the intent, in the same transaction as the decision to accept it.
- An id the client can use to ask for status.
- A fast read of data you already have.
What leaves: sending mail, calling a payment or a model, rendering a large file, fan-out to other systems, anything you would want to retry without the user clicking again. The worker uses the rules in Retry a Call Only When the Call Is Safe. The request does not loop.
Illustrative scenario
This scenario is illustrative. A user asks for a report. The request checks that they may see those rows, writes a report row in status queued, and returns 202 with the id. A worker builds the file, stores it, and sets status ready or failed. If the worker dies, the row is still queued and another worker can claim it. The user refreshes the report page. They are not holding a request open across the build. A model summary of the report, if you add one, is another job with its own status, not a blocking call inside the click. Whether the user should wait at all is Decide Whether the User Should Wait.
Checklist
- List every side effect in the handler. Mark the ones that can exceed a short deadline.
- Record intent before you perform the side effect.
- Give the job an id, a status, and a safe retry.
- Make "failed" visible to the user who asked.
- Do not send the email and the database write as one unspoken transaction. They are not one.
- Measure how long jobs sit queued. A queue you never look at is a silent backlog.
Questions that usually come next
Is a background thread inside the web process enough?
It is enough until the process restarts and the thread dies with the work half done. A durable queue survives that restart. An in-memory thread does not.
What should the client receive immediately?
An acceptance and a place to look. 202 with a status URL is a clear shape. 200 that means "maybe still working" is how clients time out and retry the whole submission.
Direct answers
Is a background thread inside the web process enough?
Not for work that must survive a restart. Put that work on a durable queue. An in-process thread dies with the process.
What should the client receive immediately?
Acceptance and a status URL. A 200 that is still working invites the client to submit the same request again.
References & Prior Art
RFC 9110: HTTP Semantics
R. Fielding, M. Nottingham, J. Reschke • IETF (2022)
Vikas
Software EngineerVikas focuses on event architectures, webhook idempotency, queue resilience, and sequential product development workflows at Vasiva.