Repository navigation
Let retry policies skip a task - #74740
Open
sdaberdaku wants to merge 1 commit into
Open
sdaberdaku wants to merge 1 commit into
sdaberdaku wants to merge 1 commit into
Conversation
sdaberdaku
force-pushed
the
retry-policy-skip-action
branch
3 times, most recently
from
October 16, 2026 15:34
a3ea87d to
8a5007d
Compare
Contributor
Author
|
@pankajastro, since you reviewed the |
sdaberdaku
force-pushed
the
retry-policy-skip-action
branch
3 times, most recently
from
October 17, 2026 14:16
fad929a to
56648ce
Compare
sdaberdaku
force-pushed
the
retry-policy-skip-action
branch
from
October 27, 2026 06:36
56648ce to
5ae26c4
Compare
2 tasks done
sdaberdaku
force-pushed
the
retry-policy-skip-action
branch
2 times, most recently
from
October 29, 2026 13:45
3fac0b9 to
c50a006
Compare
A retry policy already maps an exception to RETRY, FAIL or RESCHEDULE, but a domain exception that means "nothing to do" still has to raise AirflowSkipException from inside business code, or be translated by a try/except in every task body. RetryAction.SKIP lets the same policy object end the task as skipped, so the whole exception-to-outcome mapping lives in one reusable place and the policy's reason is stored on the task instance like it is for RETRY and FAIL. The SKIPPED terminal state, retry_reason persistence, on_skipped_callback and the skipped listener hook all exist already, so nothing changes in the API server or serialization.
sdaberdaku
force-pushed
the
retry-policy-skip-action
branch
from
November 7, 2026 10:28
c50a006 to
c65828c
Compare
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Follow-up to AIP-105 (#65474),
ChainRetryPolicy(#73508) andRetryAction.RESCHEDULE(#74719). A retry policy can now end a task asskipped.Summary
RetryAction.SKIP(and theRetryDecision.skip(reason=...)helper) marks the taskSKIPPEDinstead of failing or retrying it. No retry is consumed, failure callbacks and failure metrics do not fire,on_skipped_callbackand the skipped listener hook run, and downstream tasks see a skipped upstream as they do forAirflowSkipException. The decision'sreasonis stored asretry_reason, as it already is forRETRYandFAIL.Why
A task can raise one of three Airflow exceptions to end some way other than a plain failure:
AirflowFailException,AirflowRescheduleExceptionandAirflowSkipException. A retry policy can now choose the first two outcomes itself, withFAIL(AIP-105) andRESCHEDULE(#74719).SKIPadds the third, so every one of these outcomes can come from a domain exception without business code importing Airflow's.#74719 made this case for reschedule: without it, the only way was to subclass the operator and raise
AirflowRescheduleException. Skipping has the same problem today. A domain exception that means "nothing to do" (no input for this partition, upstream source unchanged, feature flag off) has to raiseAirflowSkipExceptionfrom inside business code, which ties that code to Airflow, or be caught by atry/exceptin every task body. WithSKIP, the whole exception-to-outcome mapping lives in one reusable policy object attached to the task.How it differs from RESCHEDULE
RESCHEDULEneedsmax_reschedulesorreschedule_timeoutbecause a broad rule could otherwise loop forever.SKIPends the task, so it cannot loop and adds no fields toRetryDecisionorRetryRule. A broadSKIPrule can hide real bugs as skips, so the docs say to match narrow exception types.RESCHEDULEonly logs its reason becauseRescheduleTaskhas no field for it.SKIPsends aTaskState, which already carriesretry_reason.AirflowSkipException. If the final state never reaches the supervisor, the scheduler finds the task still running when the worker exits and fails it: retried if retries remain, otherwise failed. Downstream tasks do not run.What changes
RetryAction.SKIPandRetryDecision.skip()inairflow/sdk/definitions/retry_policy.py._handle_current_task_failedintask_runner.pyreturns the sameTaskState(state=SKIPPED, ...)theAirflowSkipExceptionpath returns, carrying the policy reason. The existingfinalizepath handles callbacks and listeners.ChainRetryPolicyalready treats any non-DEFAULTdecision as the winner, so only its docstring changes.SKIPentry in the retry-policy section ofcore-concepts/tasks.rst, plus a rule inexample_retry_policy.py.No API server, serialization, migration or UI change.
TITerminalStatePayloadalready acceptsSKIPPEDand the route already persistsretry_reasonfor any terminal payload.AirflowFailExceptionandAirflowSensorTimeoutkeep bypassing the policy, as today.Tests
test_retry_policy.py:RetryDecision.skip(), aSKIPrule survivingserialize()/deserialize(),ChainRetryPolicyletting aSKIPwin, and_handle_current_task_failedreturningSKIPPEDwith the reason even whenshould_retryis true.test_task_runner.py: an end-to-endrun()with aSKIPrule endsSKIPPED, carriesretry_reason, and emits noti_failuresmetric.Run locally on the current
main: both task-sdk test files (657 passed withTZ=UTC) andprek run --from-ref main --stage pre-commit, which includes mypy fortask-sdkandairflow-core. Before rebasing onto #74719, the corealways,serializationand Execution API tests that touch retry policies and example Dags, and the manual prek stage, also passed; those have not been re-run since.TestTriggerDagRunOperatorintest_task_runner.pyalso fails onmainwhen the host is not on UTC, and passes withTZ=UTC; it is unrelated to this change.closes: #75796
Was generative AI tooling used to co-author this PR?
Generated-by: Claude Code (Fable 5.1, Opus 5.5) following the guidelines