This is an automated email from the ASF dual-hosted git repository.

kaxilnaik pushed a commit to branch v3-0-test
in repository https://gitbox.apache.org/repos/asf/airflow.git

commit f2cae5f3c4caef466025fd2e27c8886fc2b76665
Author: jj.lee <[email protected]>
AuthorDate: Thu May 1 01:59:27 2025 +0900

    Fix ContinuousTimetable false triggering when last run ends in future 
(#45175)
    
    closes: #45081
    (cherry picked from commit 0e846a4520cd0a33cb73f22b1404eb01cad4b561)
---
 airflow-core/src/airflow/timetables/simple.py           | 17 ++++++++++++-----
 .../tests/unit/timetables/test_continuous_timetable.py  | 11 +++++++++++
 2 files changed, 23 insertions(+), 5 deletions(-)

diff --git a/airflow-core/src/airflow/timetables/simple.py 
b/airflow-core/src/airflow/timetables/simple.py
index 49dcda81a4f..0dfcd6060de 100644
--- a/airflow-core/src/airflow/timetables/simple.py
+++ b/airflow-core/src/airflow/timetables/simple.py
@@ -135,14 +135,21 @@ class ContinuousTimetable(_TrivialTimetable):
     ) -> DagRunInfo | None:
         if restriction.earliest is None:  # No start date, won't run.
             return None
+
+        current_time = timezone.coerce_datetime(timezone.utcnow())
+
         if last_automated_data_interval is not None:  # has already run once
-            start = last_automated_data_interval.end
-            end = timezone.coerce_datetime(timezone.utcnow())
+            if last_automated_data_interval.end > current_time:  # start date 
is future
+                start = restriction.earliest
+                elapsed = last_automated_data_interval.end - 
last_automated_data_interval.start
+
+                end = start + elapsed.as_timedelta()
+            else:
+                start = last_automated_data_interval.end
+                end = current_time
         else:  # first run
             start = restriction.earliest
-            end = max(
-                restriction.earliest, 
timezone.coerce_datetime(timezone.utcnow())
-            )  # won't run any earlier than start_date
+            end = max(restriction.earliest, current_time)
 
         if restriction.latest is not None and end > restriction.latest:
             return None
diff --git a/airflow-core/tests/unit/timetables/test_continuous_timetable.py 
b/airflow-core/tests/unit/timetables/test_continuous_timetable.py
index 767dc251925..73a4be5ea48 100644
--- a/airflow-core/tests/unit/timetables/test_continuous_timetable.py
+++ b/airflow-core/tests/unit/timetables/test_continuous_timetable.py
@@ -89,3 +89,14 @@ def test_no_runs_after_end_date(timetable, restriction):
     )
 
     assert next_info is None
+
+
+@time_machine.travel(BEFORE_DATE)
+def test_no_false_triggering_with_future_start_date_after_run(timetable, 
restriction):
+    next_info = timetable.next_dagrun_info(
+        last_automated_data_interval=DataInterval(BEFORE_DATE, 
BEFORE_DATE.add(hours=1)),
+        restriction=restriction,
+    )
+
+    assert next_info is not None
+    assert next_info.data_interval.start == START_DATE

Reply via email to