Execution model
Job separates task intent from task delivery. Your app declares task handlers. The Job Product Worker records run state, sends delivery messages, executes handlers from Queue events, and records attempt results.
jobs.enqueue(...) -> Job Product RPC -> layeron_job_runs insert -> Queue Product send -> Job Product Worker queue event -> layeron_job_attempts insert -> task handler -> run status updateA task is a named handler:
jobs.task("resize-image", {}, async (payload, ctx) => { await resizeImage(payload.objectKey)})Task names are stable product metadata. Choose names that describe the work,
such as deliver-webhook, send-email, resize-image, or sync-provider.
A run is one execution request:
const run = await jobs.enqueue("resize-image", { objectKey: "uploads/avatar.png",})Run states:
| Status | Meaning |
|---|---|
queued | The run is ready for delivery. |
scheduled | The run has a future execution time. |
running | A task handler is executing. |
succeeded | The task handler completed. |
retrying | The latest attempt failed and another attempt is scheduled. |
canceled | The run was canceled. |
dead_lettered | The run exhausted attempts. |
Attempt
Section titled “Attempt”An attempt is one try at a run. Attempts have their own IDs and timing. A run
with attempts: 5 can produce up to five attempt records.
The task context exposes attempt metadata:
jobs.task("sync-provider", {}, async (payload, ctx) => { await syncProvider(payload.accountId, { runId: ctx.runId, attempt: ctx.attempt, })})Delivery
Section titled “Delivery”Job uses Queue for delivery. Queue handles delayed delivery and wakes the Job Product Worker. Job owns the run state and retry decision.
This split keeps task execution durable:
- enqueue returns after the run is recorded and delivery is requested.
- Queue delivery can happen outside the original request.
- failed attempts update Job state before retry.
- exhausted attempts become
dead_letteredfor inspection and replay.
Idempotency
Section titled “Idempotency”Use idempotencyKey when the same business event can enqueue the same work
more than once:
await jobs.enqueue("deliver-webhook", payload, { idempotencyKey: `webhook:${payload.endpointId}:${payload.eventId}`,})When the key already exists for the Job instance, Job returns the existing run
metadata with deduped: true.