Fix missing task.queued_duration metric in Airflow 3#67592
Conversation
|
Congratulations on your first Pull Request and welcome to the Apache Airflow community! If you have any issues or are unsure about any anything please check our Contributors' Guide
|
|
@eladkal gentle ping! Could you help trigger CI? |
0576c5e to
2988b04
Compare
|
@ashb Gentle ping! This has approval from @henry3260, would appreciate a look when you have a moment. The 4 failing checks are unrelated flaky test_wasb failures. |
The metric was only emitted by TaskInstance.emit_state_change_metric, which was only called from the legacy LocalTaskJob path (_check_and_change_state_before_execution). Airflow 3 workers run via the Task SDK and supervisor, which flip TI state to RUNNING through the ti_run Execution API endpoint instead — that path bypassed the emit site, so task.queued_duration (and its registry-derived legacy name dag.<dag_id>.<task_id>.queued_duration) stopped firing entirely. Emit the metric from the ti_run endpoint at the moment it flips state from QUEUED to RUNNING. The scheduler refreshes queued_dttm on every queueing, so utcnow() - queued_dttm is a meaningful queue wait for first runs and retries alike — matching the legacy emit, which fired on every transition to RUNNING. Only resumes from deferral are skipped (identified by next_method, set by the trigger on resume) to avoid re-emitting within the same try, plus the rare case of a missing queued_dttm.
2988b04 to
5f57b80
Compare
|
@ashb thanks for the review! On the On the test: |
|
@ashb Gentle ping — I've addressed both your comments: dropped the |
Summary
task.queued_duration(and its registry-derived legacy namedag.<dag_id>.<task_id>.queued_duration) stopped firing entirely after the Airflow 3 worker switched to the Task SDK / supervisor / Execution API.The metric was only emitted by
TaskInstance.emit_state_change_metric, which is only reachable from_check_and_change_state_before_execution— the legacy LocalTaskJob path. Airflow 3 workers flip TI state toRUNNINGthrough theti_runExecution API endpoint instead, which bypasses the emit site.This is the same regression pattern as #62019 (missing
ti.start/ti.finish).Fix
Emit
task.queued_durationfromti_runat the moment it transitions the TI from QUEUED to RUNNING. Skip the emit on transitions that are not the genuine first run of a try:end_date;next_method(the trigger sets it andend_datestaysNoneacross a deferral, soend_datealone cannot catch it);queued_dttm(rare race / test setups).The legacy dotted name is emitted automatically by
stats.timingvia themetrics_template.yamlregistry — no manual second call needed.Test plan
test_ti_run_emits_queued_duration_metricconfirmed to fail before the fix and pass after (verified by stashing the production change and re-running the test).test_ti_run_skips_queued_duration_metriccovers all three skip conditions (end_dateset /deferral_resume/queued_dttmmissing).TestTIRunStatetests still pass.ruff format/ruff check/mypy-airflow-core/prek run --from-ref upstream/main --stage pre-commitall green.closes: #63503
closes: #66067
Was generative AI tooling used to co-author this PR?
Generated-by: Claude Code (Opus 4.7) following the guidelines
Important
🛠️ Maintainer triage note for @myps6415 · by
@potiuk· 2026-07-02 17:46 UTCSome review feedback from
@ashb,@henry3260is waiting on you:@ashb,@henry3260need a reply or a fix.The ball is in your court — you've been assigned to this PR. Reply or push a fix in each thread, then mark them resolved.
Automated triage — may be imperfect; a maintainer takes the next look.