Job context
Every handler receives a worker.JobContext as its last argument. It carries
per-execution metadata, the cancellation signal, a progress sink, and a
job-scoped logger. The runtime constructs it — you never build one yourself.
JobContext embeds context.Context, so you can pass it (or its .Context)
directly to any context-aware call.
func(ctx context.Context, p Payload, jc worker.JobContext) error {
jc.Logger.Info("starting")
jc.ReportProgress(0.25)
return doWork(ctx, p) // ctx is the cancelling context
}
Fields
| Field | Type | Meaning |
|---|---|---|
Context | context.Context | Cancelled on timeout, shutdown, or a server cancel. Embedded — usable as the handler's ctx. |
JobID | string | Unique id of this job execution. Use it as the idempotency key. |
JobType | string | The registered type string this job dispatched to. |
Attempt | int | 1-based attempt number. |
MaxAttempts | int | Configured maximum attempts for this job. |
EnqueuedAt | string | When the job was enqueued (RFC-3339). Kept as a string and parsed on demand, so a malformed timestamp never disrupts dispatch. |
Logger | *slog.Logger | A logger pre-bound with the job id and type, so handler logs correlate automatically. |
Cancellation
The embedded context is cancelled when:
- the per-job timeout elapses,
- the host is shutting down, or
- the server returns a cancel directive on a heartbeat.
Cancellation is cooperative. Honour the context in every blocking call:
select {
case <-ctx.Done():
return ctx.Err()
case res := <-work:
return handle(res)
}
A handler that ignores its context keeps running until the server reclaims the job — and it holds a concurrency slot until it returns.
Progress
jc.ReportProgress(f) records fractional progress in [0, 1]. The value is
surfaced on the next heartbeat and shown on the dashboard.
jc.ReportProgress(0.5)
- Out-of-range or non-finite values (
≤ 0,> 1,NaN,±Inf) are ignored — progress is simply not reported until a valid value is set. - The latest valid value wins. There is no client-side requirement that progress only increase; the server treats reported progress as monotonic.
See Heartbeats & progress for the cadence details.
Logging
jc.Logger is a *slog.Logger bound with job_id and job_type, so anything
you log inside the handler carries those fields:
jc.Logger.Info("charged customer", "amount_cents", 1999)