Job context
Every handler receives a JobContext as its last argument. The worker
constructs it for each execution — you never build one yourself.
from zeridion_flare.worker import JobContext
@worker.job("SendWelcomeEmail")
def send_welcome(payload, ctx: JobContext) -> None:
ctx.logger.info("starting job %s", ctx.job_id)
ctx.report_progress(0.5)
if ctx.is_cancelled():
return
...
ctx.report_progress(1.0)
Metadata
| Attribute | Type | Description |
|---|---|---|
job_id | str | Unique id for this execution. |
attempt | int | Which attempt this is (starts at 1). |
max_attempts | int | Attempt ceiling for the job. |
enqueued_at | datetime | None | When the job was enqueued (time-zone aware; None if the timestamp was missing or unparseable). |
job_type | str | The job-type string for this execution. |
logger | logging.Logger | A logger pre-bound with the job's id and type so handler logs correlate automatically. |
Reporting progress
ctx.report_progress(0.25)
Progress is a fraction from 0.0 to 1.0 and surfaces on the dashboard while
the job runs. The latest value rides the next heartbeat. Values outside the
range are ignored — 0 or negative is treated as "no update", and anything
above 1.0 is clamped to 1.0. The most recent valid value wins.
Cancellation
A job can be cancelled while it runs — when it exceeds its timeout, when the server asks to cancel it, or when the worker is shutting down. Because Python threads cannot be safely killed, cancellation is cooperative: your handler has to check for it.
@worker.job("ProcessLargeBatch")
def process_batch(payload, ctx: JobContext) -> None:
for row in rows:
if ctx.is_cancelled():
return # stop promptly
do_work(row)
# Prefer the interruptible sleep over time.sleep so a cancel is noticed:
if ctx.cancellation.sleep(5.0):
return # woke early because cancelled
The cancellation handle exposes:
| Member | Behaviour |
|---|---|
ctx.is_cancelled() | True once cancellation has been requested. |
ctx.raise_if_cancelled() | Raises if cancellation has been requested. |
ctx.cancellation.sleep(seconds) | Interruptible sleep; returns True if cancelled before the time elapsed. |
ctx.cancellation.register(closer) | Registers a callback (e.g. to close a socket) invoked when cancellation is requested. |
A CPU-bound handler that never yields cannot be interrupted. It keeps running until it finishes, after which the worker reclaims its slot. The server has its own reclaim window for a job that stops reporting, so the job will be retried elsewhere even if a wedged handler can't be stopped locally. For hard, immediate cancellation, run such work in a separate process.
Idempotency
Because the final acknowledgement is best-effort, a job can be delivered more
than once. Use ctx.job_id to make side effects idempotent — record that the
work for an id was done, and skip it on a redelivery.