Description
Correction (2026-09-02): the original version of this issue was wrong about the common case —
see below. I originally claimed CronDataIntervalTimetable/DeltaDataIntervalTimetable "always
wait for the next boundary" on first run under catchup=False, by analogy with
CronTriggerTimetable's run_immediately parameter. I verified this against actual runtime
behavior instead of just reading docstrings, and that claim is false for the two most common
setups: no explicit start_date, or a start_date from long in the past. In both cases,
CronDataIntervalTimetable._skip_to_latest() already schedules the most-recently-completed period
immediately — functionally equivalent to run_immediately=True by default, no toggle needed.
There is a real, much narrower edge case, though: when start_date is set to a value that falls
inside the currently in-progress period (e.g. deploying a DAG with start_date a few hours
ago, catchup=False), _align_to_next(earliest) skips the in-progress period entirely — it only
considers periods that start at or after start_date — which pushes the first run out to nearly
two full periods later, not one. Concretely, for @daily, deploying at start_date = now - 3h today doesn't produce a first run for today's or tomorrow's data, it produces one for the
day-after-tomorrow.
Verified with a script run through breeze testing core-tests, calling
CronDataIntervalTimetable("@daily", timezone="UTC").next_dagrun_info(...) directly with
last_automated_data_interval=None, restriction.catchup=False:
start_date |
first run's data interval |
delay |
None |
yesterday → today (already complete) |
none — fires immediately |
| long in the past |
yesterday → today (already complete) |
none — fires immediately |
now - 3h (today) |
day-after-tomorrow's full period |
~2 periods |
Use case/motivation
I don't know if this is intentional (only ever run "clean" full periods that start entirely after
start_date, never a period the DAG only existed for part of) or an oversight — I couldn't find
prior discussion either way. If it's intentional, this issue should probably just be closed. If
not, the CronTriggerTimetable-style _calc_first_run() — which chooses between the past-tick and
next-tick based on run_immediately / proximity — is a fix pattern already proven for the trigger
timetables and could plausibly be adapted rather than invented fresh, though I haven't scoped that
out since it depends on the answer above.
Apologies for the churn on the original framing — flagging here rather than silently closing so
there's a record of what was actually verified, in case the mid-period edge case is useful signal.
Related issues
None found.
Are you willing to submit a PR?
(Holding off on a PR until there's a read on whether the mid-period behavior above is intended.)
Code of Conduct
Description
Correction (2026-09-02): the original version of this issue was wrong about the common case —
see below. I originally claimed
CronDataIntervalTimetable/DeltaDataIntervalTimetable"alwayswait for the next boundary" on first run under
catchup=False, by analogy withCronTriggerTimetable'srun_immediatelyparameter. I verified this against actual runtimebehavior instead of just reading docstrings, and that claim is false for the two most common
setups: no explicit
start_date, or astart_datefrom long in the past. In both cases,CronDataIntervalTimetable._skip_to_latest()already schedules the most-recently-completed periodimmediately — functionally equivalent to
run_immediately=Trueby default, no toggle needed.There is a real, much narrower edge case, though: when
start_dateis set to a value that fallsinside the currently in-progress period (e.g. deploying a DAG with
start_datea few hoursago, catchup=False),
_align_to_next(earliest)skips the in-progress period entirely — it onlyconsiders periods that start at or after
start_date— which pushes the first run out to nearlytwo full periods later, not one. Concretely, for
@daily, deploying atstart_date = now - 3htoday doesn't produce a first run for today's or tomorrow's data, it produces one for theday-after-tomorrow.
Verified with a script run through
breeze testing core-tests, callingCronDataIntervalTimetable("@daily", timezone="UTC").next_dagrun_info(...)directly withlast_automated_data_interval=None,restriction.catchup=False:start_dateNonenow - 3h(today)Use case/motivation
I don't know if this is intentional (only ever run "clean" full periods that start entirely after
start_date, never a period the DAG only existed for part of) or an oversight — I couldn't findprior discussion either way. If it's intentional, this issue should probably just be closed. If
not, the
CronTriggerTimetable-style_calc_first_run()— which chooses between the past-tick andnext-tick based on
run_immediately/ proximity — is a fix pattern already proven for the triggertimetables and could plausibly be adapted rather than invented fresh, though I haven't scoped that
out since it depends on the answer above.
Apologies for the churn on the original framing — flagging here rather than silently closing so
there's a record of what was actually verified, in case the mid-period edge case is useful signal.
Related issues
None found.
Are you willing to submit a PR?
(Holding off on a PR until there's a read on whether the mid-period behavior above is intended.)
Code of Conduct