Skip to content

Celery

Package: z4j-celery - Celery 5.0+.

Terminal window
pip install z4j-celery

Auto-discovered. No explicit registration needed if you use z4j-django / z4j-flask / z4j-fastapi.

Signalz4j event
before_task_publishtask_sent
task_preruntask_started
task_postrun (state=SUCCESS)task_succeeded
task_postrun (state=FAILURE)task_failed
task_retrytask_retry
task_revokedtask_revoked

Plus the payload: args, kwargs (redacted), queue, routing key, exchange, retries count, ETA, expires, task parent (chord / group support).

VerbHow z4j performs it
retryapp.send_task(name, args, kwargs, ...) with original payload; marks old task retried_as=<new_id>
cancelapp.control.revoke(task_id, terminate=False) - worker-level cancellation
cancel + terminaterequires operator+ role - sends SIGTERM to the worker
purge_queueapp.control.purge() on the queue
bulk_retryloop native retry, capped at 10k

Celery’s chord and group primitives carry a group_id. z4j preserves this, letting the dashboard:

  • Show sub-tasks grouped under the parent.
  • Offer “retry whole chord” as a single button.
  • Attribute failures to the root group in alerts (v1.1 feature).
  • Canvas signatures - .si() / .s() are not re-serialized exactly; the agent captures the resolved payload from before_task_publish. Re-enqueueing re-runs with the same captured args, not the same signature object. This is fine 99% of the time.
  • eta/countdown on retry - z4j’s retry does not replay the original ETA. Retries run immediately.
  • Broker state visibility - queue length reporting requires redis broker; RabbitMQ support works but depends on rabbitmq-management plugin.

The adapter takes no explicit config - it reads the Celery app’s config via the framework adapter.

To select a specific Celery app (multiple apps in one process):

# Django settings
Z4J = {
...,
"celery": {"app": "myproject.celery.app"}, # dotted path
}
  • Event capture adds ~50µs per task (measured on Apple M3). Negligible.
  • task_postrun signal is synchronous in Celery; the z4j handler does its work on a worker thread to avoid blocking.

See scheduler: celery-beat.