amoghrajesh commented on code in PR #73027:
URL: https://github.com/apache/airflow/pull/73027#discussion_r4043896097


##########
airflow-core/src/airflow/api_fastapi/execution_api/routes/task_instances.py:
##########
@@ -670,7 +670,9 @@ def _create_ti_state_update_query_and_update_state(
         query = query.values(state=updated_state, next_method=None, 
next_kwargs=None)
 
         if updated_state == TaskInstanceState.FAILED:
-            # This is the only case needs extra handling for 
TITerminalStatePayload
+            if isinstance(ti_patch_payload, TITerminalStatePayload) and 
ti_patch_payload.retry_reason:
+                failed_retry_reason: str | None = 
ti_patch_payload.retry_reason[:500]

Review Comment:
   Handled in baa26759fd



##########
airflow-core/src/airflow/api_fastapi/execution_api/routes/task_instances.py:
##########
@@ -670,7 +670,9 @@ def _create_ti_state_update_query_and_update_state(
         query = query.values(state=updated_state, next_method=None, 
next_kwargs=None)
 
         if updated_state == TaskInstanceState.FAILED:
-            # This is the only case needs extra handling for 
TITerminalStatePayload
+            if isinstance(ti_patch_payload, TITerminalStatePayload) and 
ti_patch_payload.retry_reason:
+                failed_retry_reason: str | None = 
ti_patch_payload.retry_reason[:500]
+                query = query.values(retry_reason=failed_retry_reason)

Review Comment:
   Handled in baa26759fd



##########
task-sdk/src/airflow/sdk/execution_time/schema/versions/v2026_10_30.py:
##########
@@ -34,3 +35,11 @@ class AddArgBindingsToSupervisorTIRunContext(VersionChange):
     description = __doc__
 
     instructions_to_migrate_to_previous_version = 
(schema(TIRunContext).field("arg_bindings").didnt_exist,)
+
+
+class AddRetryReasonToTaskState(VersionChange):
+    """Add `retry_reason` to `TaskState`."""
+
+    description = __doc__
+
+    instructions_to_migrate_to_previous_version = 
(schema(TaskState).field("retry_reason").didnt_exist,)

Review Comment:
   Handled in baa26759fd



##########
airflow-core/src/airflow/api_fastapi/execution_api/versions/v2026_10_30.py:
##########
@@ -52,3 +52,13 @@ class AddCallbackRunEndpoint(VersionChange):
     instructions_to_migrate_to_previous_version = (
         endpoint("/callbacks/{callback_id}/run", ["PATCH"]).didnt_exist,
     )
+
+
+class AddTerminalStateRetryReasonField(VersionChange):
+    """Add the `retry_reason` field to TITerminalStatePayload for failed 
retry-policy decisions."""
+
+    description = __doc__
+
+    instructions_to_migrate_to_previous_version = (
+        schema(TITerminalStatePayload).field("retry_reason").didnt_exist,

Review Comment:
   Handled in baa26759fd



##########
task-sdk/tests/task_sdk/execution_time/test_task_runner.py:
##########
@@ -1196,6 +1196,65 @@ def execute(self, context):
     assert counted.count("operator_failures") == 1
 
 
+def test_retry_policy_fail_persists_reason(create_runtime_ti, 
mock_supervisor_comms):
+    class _AlwaysFails(BaseOperator):
+        def execute(self, context):
+            raise RuntimeError("boom")
+
+    task = _AlwaysFails(
+        task_id="fail_with_reason",
+        retry_policy=ExceptionRetryPolicy(
+            rules=[RetryRule(exception=RuntimeError, action=RetryAction.FAIL, 
reason="do not retry")]
+        ),
+    )
+    ti = create_runtime_ti(task=task, should_retry=True)

Review Comment:
   Handled in baa26759fd



##########
task-sdk/tests/task_sdk/execution_time/test_task_runner.py:
##########
@@ -1196,6 +1196,65 @@ def execute(self, context):
     assert counted.count("operator_failures") == 1
 
 
+def test_retry_policy_fail_persists_reason(create_runtime_ti, 
mock_supervisor_comms):
+    class _AlwaysFails(BaseOperator):
+        def execute(self, context):
+            raise RuntimeError("boom")
+
+    task = _AlwaysFails(
+        task_id="fail_with_reason",
+        retry_policy=ExceptionRetryPolicy(
+            rules=[RetryRule(exception=RuntimeError, action=RetryAction.FAIL, 
reason="do not retry")]
+        ),
+    )
+    ti = create_runtime_ti(task=task, should_retry=True)
+
+    state, msg, error = run(ti, ti.get_template_context(), mock.MagicMock())
+
+    assert state == TaskInstanceState.FAILED
+    assert isinstance(msg, TaskState)
+    assert msg.retry_reason == "do not retry"
+
+
+def 
test_retry_policy_retry_exhausted_persists_combined_reason(create_runtime_ti, 
mock_supervisor_comms):
+    """A policy-chosen RETRY that hits an exhausted budget still fails, with 
both reasons recorded."""
+
+    class _AlwaysFails(BaseOperator):
+        def execute(self, context):
+            raise RuntimeError("boom")
+
+    task = _AlwaysFails(
+        task_id="retry_exhausted",
+        retry_policy=ExceptionRetryPolicy(
+            rules=[RetryRule(exception=RuntimeError, action=RetryAction.RETRY, 
reason="rate limit")]
+        ),
+    )
+    ti = create_runtime_ti(task=task, try_number=3, max_tries=2, 
should_retry=False)
+
+    state, msg, error = run(ti, ti.get_template_context(), mock.MagicMock())
+
+    assert state == TaskInstanceState.FAILED
+    assert isinstance(msg, TaskState)
+    assert msg.retry_reason == "rate limit; retries exhausted (3 of 3)"
+
+
+def test_plain_retries_exhausted_has_no_reason(create_runtime_ti, 
mock_supervisor_comms):
+    """Without a retry policy, exhausting the retry budget must not synthesize 
a reason."""
+
+    class _AlwaysFails(BaseOperator):
+        def execute(self, context):
+            raise RuntimeError("boom")
+
+    task = _AlwaysFails(task_id="plain_exhausted")
+    ti = create_runtime_ti(task=task, try_number=3, max_tries=2, 
should_retry=False)
+
+    state, msg, error = run(ti, ti.get_template_context(), mock.MagicMock())
+
+    assert state == TaskInstanceState.FAILED
+    assert isinstance(msg, TaskState)
+    assert msg.retry_reason is None

Review Comment:
   Handled in baa26759fd



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to