Skip to content

Preserve sensor start_date when scheduler advances reschedule to queued - #66790

Closed
1fanwang wants to merge 2 commits into
apache:mainfrom
1fanwang:fix/reschedule-start-date-multi-scheduler
Closed

1fanwang wants to merge 2 commits into
apache:mainfrom
1fanwang:fix/reschedule-start-date-multi-scheduler

Conversation

@1fanwang

@1fanwang 1fanwang commented May 12, 2026 •

Copy link
Copy Markdown
Contributor

Fixes #66784.

A sensor in mode="reschedule" loses its first-poke start_date on every re-execution: each poke writes start_date=utcnow() through the run path, so the value drifts forward to the last poke. dagrun.first_task_scheduling_delay then grows by the reschedule wait time, which makes scheduling-delay dashboards too high for any Dag fronted by a reschedule-mode sensor.

What

When a task has prior reschedule history, its first-poke start_date is restored instead of accepting the per-poke utcnow(). This applies to both the worker run path and the legacy execution path. Deferred tasks already had an equivalent guard; rescheduled tasks did not. The older reschedule guard never fired because the scheduler advances the task past UP_FOR_RESCHEDULE before the worker runs it.

End-to-end repro

Real airflow standalone (scheduler -> LocalExecutor -> supervisor -> Execution API), with a scheduled Dag fronted by a reschedule-mode PythonSensor gated to succeed after 3 reschedules. start_date and the emitted StatsD metric are read from the live run, not fabricated rows.

start_date drift emitted delay true delay inflation
Before +37.4s 69.6s 32.2s +37.4s
After 0.0s 100.0s 100.0s 0.0s
Raw before / after snapshots
BEFORE (no fix)
task_instance.start_date  = 2026-06-13 17:30:20.834768   <-- last poke
task_reschedule first row start_date = 2026-06-13 17:29:43.418821   <-- first poke
dag_run.run_after = 2026-06-13 17:29:11.206203
START_DATE DRIFT (final-first) = 37.4s
emitted first_task_scheduling_delay = 69628 ms  (true delay 32.2s)

AFTER (fix)
task_instance.start_date  = 2026-06-13 17:24:54.493490   <-- pinned to first poke
task_reschedule first row start_date = 2026-06-13 17:24:54.493490   <-- first poke
dag_run.run_after = 2026-06-13 17:23:14.496505
START_DATE DRIFT (final-first) = 0.0s
emitted first_task_scheduling_delay = 99996 ms  (true delay 100.0s)

Tests

  • test_ti_run_restores_start_date_for_rescheduled_task
  • test_ti_run_uses_payload_start_date_when_no_reschedule_rows
  • test_check_and_change_state_before_execution_restores_reschedule_start_date

Prior effort

Same fix attempted in #64816 by peachchen0716 (auto-closed after inactivity); credited as co-author.

@boring-cyborg boring-cyborg Bot added area:API Airflow's REST/HTTP API area:task-sdk labels May 12, 2026
@1fanwang
1fanwang force-pushed the fix/reschedule-start-date-multi-scheduler branch from d89cd36 to 7ac3847 Compare May 13, 2026 18:55
@choo121600 choo121600 added the ready for maintainer review Set by triage when all criteria pass, or by the fork CI reconciler when fork CI is green. label May 15, 2026
@1fanwang
1fanwang force-pushed the fix/reschedule-start-date-multi-scheduler branch from 7ac3847 to c9e4c09 Compare May 16, 2026 18:44
@1fanwang
1fanwang force-pushed the fix/reschedule-start-date-multi-scheduler branch 2 times, most recently from 1aba313 to 6b3de28 Compare June 14, 2026 05:55
When a sensor runs in mode="reschedule", the supervisor sends
start_date=utcnow() on every poke. The ti_run execution-API endpoint
wrote that value through unconditionally, so ti.start_date drifted
forward on each re-execution. dagrun.first_task_scheduling_delay
(computed from start_date - queued_at) collapsed to ~0 for any DAG
fronted by a reschedule-mode sensor.

Add a reschedule guard in ti_run that mirrors the existing
deferral guard: when start_date is present in the payload and the task
has prior TaskReschedule rows, restore start_date from the first row
instead of accepting the supervisor's utcnow(). The lookup is scoped by
ti_id, and prepare_db_for_next_try clears TaskReschedule rows and
rotates ti.id on each retry, so try-number scoping is implicit and no
stale rows leak across tries. Also mirror context.start_date in the
response so the supervisor pins context["ti"].start_date to the first
poke as well.

Also drop the unreliable state guard on the same path in
_check_and_change_state_before_execution. In the normal multi-scheduler
flow the scheduler advances UP_FOR_RESCHEDULE -> QUEUED before the
worker calls this method, so refresh_from_db returns QUEUED and the
guard never fires. The TaskReschedule lookup is harmless for
non-rescheduled tasks (returns no rows), so the guard can go.

Closes apache#66784

Co-authored-by: peachchen0716 <[email protected]>

Signed-off-by: 1fanwang <[email protected]>
@1fanwang
1fanwang force-pushed the fix/reschedule-start-date-multi-scheduler branch from 6b3de28 to 9b9dfd4 Compare June 19, 2026 18:40
@github-actions

github-actions Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

This pull request has been automatically marked as stale because it has not had recent activity. It will be closed in 5 days if no further activity occurs. Thank you for your contributions.

@github-actions github-actions Bot added the stale Stale PRs per the .github/workflows/stale.yml policy file label Aug 4, 2026
@github-actions github-actions Bot removed the stale Stale PRs per the .github/workflows/stale.yml policy file label Aug 14, 2026
@potiuk potiuk added the closed because of open PR limit Closed as a one-time step of introducing the open pull request limit label Sep 25, 2026
@potiuk

potiuk commented Sep 25, 2026

Copy link
Copy Markdown
Member

Hello @1fanwang - thank you for your contributions to Apache Airflow!

The Airflow community has introduced a limit of 5 open pull requests at a time for contributors without write access to the repository. You currently have 34 open pull requests, so - as a one-time step of introducing the limit - we closed the ones where maintainers have not engaged yet:

These pull requests stay open because maintainers are already engaged in them - they count towards your limit:

This is not a judgement of you or of your changes. We never told contributors before that opening many pull requests at once was a problem, so there is nothing to feel bad about - and nothing is lost: your branches, commits and the review history stay where they are.

What we ask you to do is to make your first prioritization decision: choose which of the pull requests above matter most to you, and reopen them (up to 5 open at a time, including the ones still open) with the "Reopen pull request" button or gh pr reopen <PR_NUMBER> --repo apache/airflow. Reopen the ones you are ready to follow through - keep them rebased, respond to review comments and fix failing checks.

While your pull requests are waiting for review, the most valuable thing you can do is help in other ways - reviewing other contributors' pull requests, helping with issues, and taking part in the discussions on the devlist and Slack.

Why we introduced the limit, what it means for you and how to reopen or restore a pull request is explained in https://github.com/apache/airflow/blob/main/contributing-docs/32_open_pull_request_limit.rst.


Drafted-by: Claude Code (Opus 5); reviewed by @potiuk before posting

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:API Airflow's REST/HTTP API area:task-sdk closed because of open PR limit Closed as a one-time step of introducing the open pull request limit ready for maintainer review Set by triage when all criteria pass, or by the fork CI reconciler when fork CI is green.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Sensor reschedule: start_date reset to utcnow() on every poke (inflates first_task_scheduling_delay)

3 participants