Job admission records that a server has accepted a specific operation for later execution. It does not mean the result exists yet. A client-generated idempotency key should identify one requested business effect within a defined scope and retention window, while the server issues a stable job ID that the client can poll or observe. The state resource separates queued, running, succeeded, failed, and canceled outcomes. Authorization is checked when the job is requested and again before a private result is released.
Job Admission, Idempotency, and Status Resources
Working case
Reviewer 47 requests a 63-page permit report. The HTTP connection ends before rendering can finish. The browser retries the request after a timeout, but the server has already queued the first copy. Without an idempotency record, two expensive reports run and two email notices are sent. The server binds the reviewer, case, report revision, and idempotency key to one job row. A repeated request with the same key and same payload returns the existing job; the same key with a different revision is a conflict, not a second report.
Implementation boundary
function sameAdmittedJob(existing, request) {
return existing.tenantId === request.tenantId && existing.key === request.key &&
existing.payloadDigest === request.payloadDigest;
}
console.log(sameAdmittedJob({ tenantId: 4, key: 'r-63', payloadDigest: 'a29' }, { tenantId: 4, key: 'r-63', payloadDigest: 'b29' }));
// Output: falseCommit the job row and an outbox intent in one database transaction where the architecture uses an outbox. Return an accepted response with a status path owned by that job, not a fabricated completed document. The status representation includes a small state enum, timestamps, progress when measurable, an error category, and a result reference only after success. Polling must respect the requester and tenant on every read. Define what a duplicate request returns after the original job succeeds and how long the key record remains. A user may refresh or reopen the page without losing the job ID. A result reference should be short-lived and scoped to the authorized case.
Cost and boundaries
A unique index on tenant, requester, and idempotency key makes duplicate lookup close to O(log n) for n stored keys. Retention creates database growth, so prune keys only after their retry window and audit requirements pass. Polling every second across many open tabs can overload the status service; prefer bounded intervals, visibility-aware pause, or server push when warranted. Progress writes also cost storage and contention. Update them at meaningful checkpoints, not every rendered line. Report generation remains O(report bytes) plus query work and should have a CPU, memory, and time budget.
Failure trace
Send the same request twice before the first response returns; only one business job may exist. Reuse the key with a changed report revision and require a conflict response. Crash after the job row commits but before a queue send; the outbox relay must still publish the intent. Return an accepted response, then fail rendering; the status resource must report failure rather than keeping a perpetual queued label. Switch accounts and try reading the old status path. Expire a result link, then verify that the job record remains visible while the private file is denied.
Verification
- Duplicate requests map to one job or an explicit conflict.
- A status path is authorization checked on every read.
- An accepted job can later report a terminal failure.
Practice drill
Implement a report request for case 47 at revision 29. Persist key r-63 under the requester and return job 84. Repeat the same payload and inspect the identical job ID; change the revision and inspect a conflict. Restart the browser and reload job 84 through its authorized status path. Simulate a worker failure and verify the visible state and recovery action. Measure polling traffic with 83 concurrent reviewers.
Decision note
Admission establishes one durable intent and status identity; completion is a later, separately verifiable state.
Common Mistakes
- Treating HTTP acceptance as finished work.
- Using only a user-supplied key without payload binding.
- Returning private results from a job ID alone.
Related lessons
Background Workflow Reliability; Worker Leases, Retries, and Duplicate Effects; Poison Job Quarantine and Replay Control; Scheduled Job Overlap, Cancellation, and Compensation; Idempotent Write Requests and Lost Responses; Export and Erasure Job State.
Connected practice
Build Project: permit report job recovery and review Web Development: jobs and abuse decisions quiz.
