@@ -1596,7 +1596,8 @@ The following diagram shows the exact order of execution:
15961596 │ 4. on_success() OR ← Outcome-specific handler │
15971597 │ on_retry() OR │ │
15981598 │ on_failure() │ │
1599- │ 5. after_return() ← Always runs last │
1599+ │ 5. after_return() ← Runs last on terminal states │
1600+ │ (skipped for RETRY/REJECTED/IGNORED) │
16001601 └───────────────────────────────────────────────────────────────┘
16011602
16021603 .. important ::
@@ -1606,7 +1607,9 @@ The following diagram shows the exact order of execution:
16061607 - All handlers run in the **same worker process ** as your task
16071608 - ``before_start `` **blocks ** the task - ``run() `` won't start until it completes
16081609 - Result backend is updated **before ** ``on_success ``/``on_failure `` - other clients can see the task as finished while handlers are still running
1609- - ``after_return `` **always ** executes, regardless of task outcome
1610+ - ``after_return `` executes when the task reaches a terminal state.
1611+ It does not run for ``RETRY ``, ``REJECTED ``, or ``IGNORED ``. If you need
1612+ a hook that fires on every attempt, use the :signal: `task_postrun ` signal.
16101613
16111614Available handlers
16121615~~~~~~~~~~~~~~~~~~
@@ -1687,8 +1690,13 @@ Available handlers
16871690 Handler called after the task returns.
16881691
16891692 .. note ::
1690- Executes **after ** ``on_success ``/``on_retry ``/``on_failure ``. This is the
1691- final hook in the task lifecycle and **always ** runs, regardless of outcome.
1693+ Executes after the outcome-specific handler when the task reaches a
1694+ terminal state.
1695+
1696+ In practice, this means it runs after ``on_success `` or ``on_failure ``.
1697+ It is not executed for ``RETRY ``, ``REJECTED ``, or ``IGNORED `` states.
1698+ If a hook is needed for every attempt, consider using the
1699+ :signal: `task_postrun ` signal.
16921700
16931701 :param status: Current task state.
16941702 :param retval: Task return value/exception.
0 commit comments