Skip to content

Unified action surface

Every engine implements "retry" and "cancel" differently:

  • Celery - task.retry() from inside the task, or re-apply with app.send_task.
  • RQ - Queue.requeue(job_id), or job.requeue().
  • Dramatiq - no first-class retry API; middleware-based.
  • Huey - retries are configured per-task; no ad-hoc retry surface.
  • arq - no retry API; re-enqueue manually.
  • taskiq - per-task retry decorators.

z4j exposes one command vocabulary, but only when an adapter can honor the specific command without reconstructing redacted inputs or pretending a broker operation succeeded.

Four common verbs exist, gated by each adapter's advertised capabilities:

Verb Semantics
retry Re-enqueue only when the engine can recover the authoritative inputs or the operator supplies complete replacements.
cancel Invoke an engine primitive that covers the adapter's documented pending/running contract.
bulk_retry Retry an explicit brain-selected set only on adapters that implement it safely.
purge_queue Drop pending messages only where the adapter can measure and target the requested queue.

Each engine adapter advertises its capability tokens in the hello frame. When z4j dispatches a verb:

  1. Look up the target agent's capability map.
  2. If advertised, send a command frame and let the adapter call the engine API.
  3. If absent, refuse the command and hide the dashboard control.

An agent on the long-poll transport sends no hello, so its capability map is unknown. The dashboard still offers the control for it, and the brain delivers a retry only to a poll whose declared retry contracts cover the task's engine.

The brain stores redacted task inputs, so it does not rebuild an executable payload from its task or event rows. Retry-with-different-inputs supplies both complete replacement collections explicitly.

Every action writes an audit row with the requested command and outcome.

See API § tasks for exact endpoints.

  • If the agent is offline, the command row is still written and stays pending. A Brain on SQLite, which uses the in-process command registry, answers 503 agent_offline; a PostgreSQL Brain answers with the pending command. Either way the row is delivered if the agent reconnects before its deadline (Z4J_COMMAND_TIMEOUT_SECONDS, default 60), and the timeout sweeper closes it otherwise. Check the command on the Commands page before issuing the action again: a second command sent while the first is pending can run the action twice.
  • An agent on the long-poll transport holds no WebSocket session but is not offline while it polls: the request returns the pending command and the agent claims it on its next poll.
  • If the command times out (60s), the action records error: timeout and the audit log captures the failure. The task state is not modified.
  • A mutation timeout can be indeterminate when the broker call may still finish; the adapter reports that state instead of claiming a clean failure.
  • No blanket retry policy - the unified action surface is operator-driven. Automatic retries happen only where you arm an automation rule with a retry action, which is admin-gated, circuit-broken, and audited. For per-task backoff and attempt limits, use the engine's native retry configuration.
  • No side-effect-safety guarantees - retrying a task that already half-ran is the user's call. z4j does not introspect idempotency.