Queueing Agent Jobs with Celery or a Message Broker
Agent runs are multi-second to multi-minute workflows with variable turn counts.
Search across all documentation pages
Agent runs are multi-second to multi-minute workflows with variable turn counts.
Putting them on a job queue decouples HTTP intake from model and tool work so you can retry, scale workers, and survive process restarts.
This recipe uses Celery + Redis as a concrete broker pattern. The same design applies to RQ, Dramatiq, ARQ, Sidekiq, SQS + workers, or cloud task queues.
Accept agent work as durable jobs, process them in workers with bounded concurrency, persist status and results, and let clients poll or subscribe instead of holding open request connections through the full loop.
job_id, goal, tenant_id, priority, trace_id, optional model_hint.Minimal Celery-shaped sketch. Install versions at build (celery, Redis broker). Adjust imports if your stack differs.
# tasks.py - teaching sketch; verify Celery API at build
from celery import Celery
from dataclasses import asdict, dataclass
import time
import uuid
app = Celery("agents", broker="redis://localhost:6379/0", backend="redis://localhost:6379/1")
app.conf.worker_prefetch_multiplier = 1
app.conf.task_acks_late = True
@dataclass
class AgentJob:
job_id: str
goal: str
tenant_id: str = "default"
def run_agent_loop(goal: str) -> str:
time.sleep(0.05) # stand-in for model + tools
return f"done:{goal[:40]}"
@app.task(bind=True, max_retries=3, name="agents.run")
def run_agent_job(self, payload: dict) -> dict:
job = AgentJob(**payload)
try:
result = run_agent_loop(job.goal)
return {"job_id": job.job_id, "status": "done", "result": result}
except ConnectionError as exc:
# infrastructure only - not quality failures
raise self.retry(exc=exc, countdown=2 ** self.request.retries)
def enqueue_agent(goal: str, tenant_id: str = "default") -> str:
job = AgentJob(job_id=str(uuid.uuid4()), goal=goal, tenant_id=tenant_id)
run_agent_job.delay(asdict(job))
return job.job_id
if __name__ == "__main__":
print("enqueued", enqueue_agent("triage support ticket"))Run a worker in another process (verify flags at build):
celery -A tasks worker --loglevel=INFO --concurrency=2| Concern | Sync HTTP handler | Queued job |
|---|---|---|
| Duration | Hits gateway timeouts | Worker owns long loops |
| Retries | Awkward mid-response | Broker redelivery + policy |
| Scale | Scale web tier with work | Scale workers independently |
| Spikes | Drop or melt | Buffer with depth limits |
| Observability | One request span | Job lifecycle + run traces |
Agents are closer to workflows than to CRUD handlers.
| Broker | Strength | Watch-outs |
|---|---|---|
| Redis + Celery/RQ | Simple ops for many teams | Persistence and multi-queue design need care |
| RabbitMQ | Routing, ack semantics | More moving parts |
| SQS / cloud tasks | Managed durability | Visibility timeouts vs long agent runs |
| NATS / Kafka | High throughput streams | Different ack/consumer models; often overkill for job RPCs |
Pick durability and ops familiarity first. Agent payloads are usually small; throughput is limited by model RPM before broker limits.
Include:
job_id (also use as idempotency key).tenant_id for quotas and noisy-neighbor isolation.trace_id / run_id for observability.Exclude:
Long agent jobs interact badly with default timeouts:
Design tools as if every job may run twice.
| Failure class | Retry from queue? |
|---|---|
| Broker blip, worker OOM mid-run | Yes, with backoff and cap |
| Provider 429 with Retry-After | Often yes, delayed |
| Invalid user input | No - fail terminal |
| Model quality / wrong answer | No - that is eval/product, not infra |
| Tool business error (not found) | Usually no |
Stacking job retries on top of tool retries and model re-turns creates storms. Share budgets with Concurrency Limits and Backpressure for Agent Workers and reliability breakers.
Typical states: queued → running → done | failed | cancelled.
Expose:
job_id, status, timestampsstop_reason when failed/cancelledSeparate queues prevent one heavy class from starving interactive work. Workers can subscribe with different concurrency.
| Approach | Strength | Weakness |
|---|---|---|
| Celery/RQ + Redis (this recipe) | Familiar Python path | You own broker ops |
| Temporal / durable workflows | Strong history and timers | Heavier platform commitment |
| Cloud Tasks / SQS workers | Managed scale | Timeout and local dev friction |
| Always-on websocket agent process | Low latency chat UX | Harder horizontal scale and recovery |
In-process asyncio.Queue only | Great for demos | Dies with the process; no multi-host |
Many products combine a durable job system for work with websockets only for streaming tokens of an already-accepted job.
No. You need a durable queue, workers, and a result store. Celery is a common Python default, not a requirement.
Prefer 202 + job_id for anything that can exceed a few seconds. Stream tokens from the worker after accept if UX needs it.
Start with 0-2 for infra failures with exponential backoff. Never unlimited. Quality issues need product policy, not redelivery.
Inside the worker task. The queue owns scheduling; the framework owns the agent graph (verify current deploy patterns at build).
Persist a cancel flag workers check between turns, and revoke the broker task when supported. Pair with kill-switch design in human-in-the-loop content.
Use separate queues or weighted fair queuing. Priority fields without worker policy are decoration.
Only if max duration and cold starts fit your agent. Long loops often prefer always-on workers or durable workflow platforms.
Unit-test the pure agent function; integration-test enqueue → worker → result with a test broker or eager mode where available.
Queue depth, time-in-queue p95, success rate, cost per job, and provider 429 rate.
Queues are the front door of a worker pool. See Architecture Guide: A Horizontally Scalable Agent Worker Pool.
Stack versions: Pins from the category manifest (verify at build): OpenRouter (~315+ models, July 2026 pricing/fees); LangGraph 1.0+; CrewAI 1.14+; Microsoft Agent Framework 1.0; Vercel AI SDK 6; Pydantic AI (latest); LlamaIndex (latest); OpenAI Agents SDK (latest + MCP); MCP (Linux Foundation governance); A2A (HTTP+SSE+JSON-RPC 2.0); Solana
@solana/web3.js+@solana/spl-token.
Reviewed by Chris St. John·Last updated Jul 16, 2026