Uh oh!
There was an error while loading. Please reload this page.
Make airflow dags test wait for Human-in-the-loop input instead of hanging - #68492
Conversation
b26e9a6 to
c7a56c2CompareUh oh!
There was an error while loading. Please reload this page.
shahar1
left a comment
There was a problem hiding this comment.
Please add an AI usage statement :)
Uh oh!
There was an error while loading. Please reload this page.
kaxil
commented
Jun 14, 2026
Dropped an email reply on the dev list around it, thanks. |
Dev-iL
left a comment
There was a problem hiding this comment.
Do we want to have cli flags like --hitl-auto-approve and --hitl-auto-reject so users can test hitl dags without actually interacting with them?
958db37 to
5d936edCompare…nging Previously a HITL task that parked in awaiting_input made `airflow dags test` loop "No tasks to run. unrunnable tasks: ..." once per second forever, with no way to make progress (the in-process runner also swallows SIGTERM, so even `timeout` could not stop it). dag.test() now treats parked HITL tasks as waiting rather than unrunnable, and never resolves them itself: the run stays alive, logging which tasks await input, until a response recorded from outside flips them back to SCHEDULED -- at which point the existing loop resumes them. This matches how a parked task behaves on a real deployment, and the existing response channels work unchanged: the Required Actions UI or the HITL REST API (PATCH .../hitlDetails) of an api-server sharing the metadata database (e.g. airflow standalone). Humans and AI agents can drive HITL pipelines locally by running dags test and submitting the response through that API. Interactive console prompting in the dags test CLI is left for a follow-up.
5d936ed to
6cccc82CompareUh oh!
There was an error while loading. Please reload this page.
Backport successfully created: v3-3-testNote: As of Merging PRs targeted for Airflow 3.X In matter of doubt please ask in #release-management Slack channel.
|
…nstead of hanging (#68492) (#69104) * Make airflow dags test wait for Human-in-the-loop input instead of hanging Previously a HITL task that parked in awaiting_input made `airflow dags test` loop "No tasks to run. unrunnable tasks: ..." once per second forever, with no way to make progress (the in-process runner also swallows SIGTERM, so even `timeout` could not stop it). dag.test() now treats parked HITL tasks as waiting rather than unrunnable, and never resolves them itself: the run stays alive, logging which tasks await input, until a response recorded from outside flips them back to SCHEDULED -- at which point the existing loop resumes them. This matches how a parked task behaves on a real deployment, and the existing response channels work unchanged: the Required Actions UI or the HITL REST API (PATCH .../hitlDetails) of an api-server sharing the metadata database (e.g. airflow standalone). Humans and AI agents can drive HITL pipelines locally by running dags test and submitting the response through that API. Interactive console prompting in the dags test CLI is left for a follow-up. * Document the HITL REST API calls for responding during dags test (cherry picked from commit 63cee22) Co-authored-by: Kaxil Naik <kaxilnaik@gmail.com> Co-authored-by: Rahul Vats <43964496+vatsrahul1001@users.noreply.github.com>
…nging (apache#68492) * Make airflow dags test wait for Human-in-the-loop input instead of hanging Previously a HITL task that parked in awaiting_input made `airflow dags test` loop "No tasks to run. unrunnable tasks: ..." once per second forever, with no way to make progress (the in-process runner also swallows SIGTERM, so even `timeout` could not stop it). dag.test() now treats parked HITL tasks as waiting rather than unrunnable, and never resolves them itself: the run stays alive, logging which tasks await input, until a response recorded from outside flips them back to SCHEDULED -- at which point the existing loop resumes them. This matches how a parked task behaves on a real deployment, and the existing response channels work unchanged: the Required Actions UI or the HITL REST API (PATCH .../hitlDetails) of an api-server sharing the metadata database (e.g. airflow standalone). Humans and AI agents can drive HITL pipelines locally by running dags test and submitting the response through that API. Interactive console prompting in the dags test CLI is left for a follow-up. * Document the HITL REST API calls for responding during dags test
A task that reaches the
awaiting_inputstate (Human-in-the-loop, #68028) hangsairflow dags testforever: nothing can resume it, so the command logsNo tasks to run. unrunnable tasks: ...once per second indefinitely. The in-process task runner also swallows SIGTERM, sotimeoutcannot stop it.dag.test()now treats parked HITL tasks as waiting rather than unrunnable, and never resolves them itself: the run stays alive, logging which tasks await input, until a response recorded from outside flips them back to SCHEDULED -- the existing loop then resumes them. This is the same contract a parked task has on a real deployment, where the API response handler or the scheduler's timeout sweep performs the resume.Because the resume is the standard transition, the existing response channels work with
dags testunchanged: the Required Actions UI or the HITL REST API of an api-server sharing the metadata database (e.g.airflow standalone). Verified end to end in breeze:airflow dags testparks and logsWaiting for Human-in-the-loop input for tasks: ['wait_approval'], aPATCH .../hitlDetailswith{"chosen_options": ["Approve"]}against a locally startedairflow api-serverresumes it, the downstream task runs, and the run finishes successfully. This also gives AI agents a clean way to drive HITL pipelines locally: rundags test, surface the request to a human, submit the answer through the API.The change is deliberately minimal -- one hunk in the
dag.test()loop plus a contract test. Interactive console prompting in thedags testCLI (and any API additions it needs) is left for follow-up PRs.Was generative AI tooling used to co-author this PR?