Results and task states

Celery · Essentials · 10 min

Knowing what a result backend gives you, and what it costs, prevents both blocked web requests and a Redis full of unused results.

delay() returns an AsyncResult that holds the task id. With a result backend configured, you can ask about the task later, even from another process, with AsyncResult(task_id, app=app).

  • r.state: PENDING, STARTED (only if task_track_started=True), RETRY, SUCCESS, FAILURE or REVOKED.
  • r.ready(), r.successful(), r.failed().
  • r.get(timeout=10) waits for the value and re-raises the task's exception if it failed; propagate=False returns the exception instead.
  • r.result holds the return value or exception without waiting.

A subtle point: PENDING also means "unknown". Celery can't tell a queued task from a nonexistent id, so a typo in an id looks like a task waiting forever.

Avoid calling get() inside a web request (you've just moved the slow work back into the request) and never inside another task, where it can deadlock the worker pool; Celery raises an error by default when you try. Use canvas workflows to chain work instead, and have the client poll or receive a notification.

Results cost storage and network. If nobody reads a task's return value, set ignore_result=True on the task (or task_ignore_result=True globally), and set result_expires so old results are cleaned up (default one day).

Example

from celery import Celery
from celery.result import AsyncResult

app = Celery("tasks", broker="redis://localhost:6379/0",
             backend="redis://localhost:6379/1")

@app.task
def add(x, y):
    return x + y

@app.task(ignore_result=True)
def log_visit(path):
    print("visit", path)

r = add.delay(2, 3)
print(r.state)                 # PENDING (until a worker picks it up)
print(r.get(timeout=10))       # 5
print(r.state, r.successful()) # SUCCESS True

same = AsyncResult(r.id, app=app)   # e.g. from an HTTP polling endpoint
print(same.result)                  # 5

Remember

  • AsyncResult(id) lets any process check state and value
  • get() blocks and re-raises the task's exception
  • PENDING also means 'unknown id'
  • ignore_result=True for fire-and-forget tasks; set result_expires

Watch out for

  • Calling result.get() inside another task.
  • Storing results for millions of tasks nobody reads.

Check yourself

  1. An AsyncResult for a mistyped task id reports which state?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: docs.celeryq.dev/en/stable/userguide/tasks.html#task-states