sdaberdaku opened a new pull request, #74740:
URL: https://github.com/apache/airflow/pull/74740

   Follow-up to AIP-105 (#65474) and `ChainRetryPolicy` (#73508). A retry 
policy can now end a task as `skipped`.
   
   ## Summary
   
   `RetryAction.SKIP` (and the `RetryDecision.skip(reason=...)` helper) marks 
the task `SKIPPED` instead of failing or retrying it. No retry is consumed, 
failure callbacks and failure metrics do not fire, `on_skipped_callback` and 
the skipped listener hook run, and downstream tasks see a skipped upstream 
exactly as for `AirflowSkipException`. The decision's `reason` is stored as 
`retry_reason`, as it already is for `RETRY` and `FAIL`.
   
   ```python
   from airflow.sdk import ExceptionRetryPolicy, RetryAction, RetryRule
   
   retry_policy = ExceptionRetryPolicy(
       rules=[
           RetryRule(exception=NoNewDataError, action=RetryAction.SKIP, 
reason="nothing to ingest"),
           RetryRule(exception=ConnectionError, action=RetryAction.RETRY, 
retry_delay=timedelta(seconds=30)),
           RetryRule(exception=PermissionError, action=RetryAction.FAIL),
       ]
   )
   ```
   
   ## Why
   
   AIP-105 made the retry policy the one place that maps an exception to an 
outcome, but that mapping stopped at "retry" and "fail". A domain exception 
that means "nothing to do" (no input for this partition, upstream source 
unchanged, feature flag off) still had to raise `AirflowSkipException` from 
inside business code, coupling it to Airflow, or be translated by a 
`try`/`except` in every task body. With `SKIP` the whole exception-to-outcome 
mapping lives in one reusable policy object attached to the task.
   
   `FAIL` already set the precedent that a policy decides the task's outcome 
rather than only its retry count. `SKIP` is the same kind of decision.
   
   ## What changes
   
   - `RetryAction.SKIP` and `RetryDecision.skip()` in 
`airflow/sdk/definitions/retry_policy.py`.
   - `_handle_current_task_failed` in `task_runner.py` returns the same 
`TaskState(state=SKIPPED, ...)` the `AirflowSkipException` path returns, 
carrying the policy reason. The existing `finalize` path handles callbacks and 
listeners.
   - `ChainRetryPolicy` already treats any non-`DEFAULT` decision as the 
winner, so only its docstring changes.
   - Docs: a `SKIP` entry in the retry-policy section of 
`core-concepts/tasks.rst`, plus a rule in `example_retry_policy.py`.
   
   No API server, serialization, migration or UI change. 
`TITerminalStatePayload` already accepts `SKIPPED` and the route already 
persists `retry_reason` for any terminal payload. `AirflowFailException` and 
`AirflowSensorTimeout` keep bypassing the policy, as today.
   
   ## Tests
   
   - `test_retry_policy.py`: `RetryDecision.skip()`, a `SKIP` rule surviving 
`serialize()`/`deserialize()`, `ChainRetryPolicy` letting a `SKIP` win, and 
`_handle_current_task_failed` returning `SKIPPED` with the reason even when 
`should_retry` is true.
   - `test_task_runner.py`: an end-to-end `run()` with a `SKIP` rule ends 
`SKIPPED`, carries `retry_reason`, and emits no `ti_failures` metric.
   
   Run locally: both task-sdk test files, core `always`, `serialization` and 
Execution API tests touching retry policy and example Dags, `prek run 
--from-ref main` (pre-commit and manual stages, including `mypy-task-sdk`). 
`TestTriggerDagRunOperator` in `test_task_runner.py` fails on `main` too on a 
non-UTC host and passes with `TZ=UTC`; unrelated to this change.
   
   ---
   
   ##### Was generative AI tooling used to co-author this PR?
   
   - [X] Yes — Claude Code (Fable 5.1)
   
   Generated-by: Claude Code (Fable 5.1) following [the 
guidelines](https://github.com/apache/airflow/blob/main/contributing-docs/05_pull_requests.rst#gen-ai-assisted-contributions)
   


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