kaxil commented on code in PR #69821:
URL: https://github.com/apache/airflow/pull/69821#discussion_r3681509912


##########
airflow-core/src/airflow/models/trigger.py:
##########
@@ -604,10 +633,21 @@ def _submit_callback_if_necessary() -> None:
 
     def _push_xcoms_if_necessary() -> None:
         """Pushes XComs to the database if they are provided."""
-        if event.xcoms:
+        if event.xcoms and callback_type != TaskInstanceState.UP_FOR_RETRY:
             for key, value in event.xcoms.items():
                 task_instance.xcom_push(key=key, value=value)
 
+    # Send the callback before handle_failure (mirrors the scheduler 
executor-event ordering):
+    # handle_failure -> save_to_db commits, which also persists the 
DatabaseCallbackSink row atomically.
     _submit_callback_if_necessary()
+
+    if handle_via_failure:
+        # Canonical failure handling: sets UP_FOR_RETRY/FAILED by 
retry-eligibility, fires the
+        # on_task_instance_failed listener + failure metrics + Log audit row, 
and clears
+        # next_method args. Mirrors the scheduler executor-event path (PR 
#56586).
+        task_instance.handle_failure(error="Task failed via trigger event", 
session=session)

Review Comment:
   On the retry-eligible path this skips the try archival the worker-side retry 
performs: `fetch_handle_failure_context` only calls `prepare_db_for_next_try` 
when `ti.state == RUNNING` (taskinstance.py:1870), and here the TI is still 
`deferred`, so no `task_instance_history` row is written for try 1 and `ti.id` 
is not rotated. When the scheduler then makes the TI schedulable it bumps 
`try_number` to 2 (dagrun.py:2144), and `GET 
.../taskInstances/{task_id}/logs/1` 404s at log.py:157 because there is no live 
TI at try 1 and no history row to fall back on. Worth deciding whether this 
branch should archive the try itself, or route through the 
`submit_failure`/`__fail__` path that already picks up the worker-side 
machinery.



##########
airflow-core/tests/unit/models/test_trigger.py:
##########
@@ -362,6 +366,63 @@ def 
test_submit_event_task_end_callback_includes_version_data(mock_send, session
     assert request.version_data == version_data
 
 
[email protected](
+    ("retries", "expected_state", "expected_callback_type"),
+    [
+        (1, TaskInstanceState.UP_FOR_RETRY, TaskInstanceState.UP_FOR_RETRY),
+        (0, TaskInstanceState.FAILED, TaskInstanceState.FAILED),
+    ],
+)
+@patch("airflow.callbacks.database_callback_sink.DatabaseCallbackSink.send")
+def test_submit_event_task_end_failed_respects_retries(
+    mock_send, session, create_task_instance, retries, expected_state, 
expected_callback_type
+):
+    """A trigger-emitted TaskFailedEvent should respect retry-eligibility: a 
deferred task with
+    retries remaining goes UP_FOR_RETRY (on_retry_callback), not straight to 
FAILED.
+
+    Failures are routed through ``TaskInstance.handle_failure`` (mirroring the 
scheduler
+    executor-event path), so the ``on_task_instance_failed`` listener fires in 
both cases.
+    """
+    from airflow.listeners.listener import get_listener_manager
+
+    listener_callback = MagicMock()
+    get_listener_manager().pm.hook.on_task_instance_failed = listener_callback

Review Comment:
   Assigning onto `pm.hook.on_task_instance_failed` leaks past the `finally`: 
`clear()` only unregisters plugins 
(shared/listeners/src/airflow_shared/listeners/listener.py:121-124) and 
`get_listener_manager()` is `@cache`d, so the MagicMock stays on the shared 
hook relay for the rest of the pytest worker. A later test that registers a 
real listener then dies in pluggy's `_verify_hook` with `InvalidSpecError: 
Cannot spec a Mock object`. The `listener_manager` fixture in 
`tests_common/pytest_plugin.py` (or `monkeypatch.setattr`) restores the 
original hook.



-- 
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