|
91 | 91 | ) |
92 | 92 | from airflow.sdk.api.datamodels._generated import AssetEventResponse, AssetResponse |
93 | 93 | from airflow.sdk.definitions.callback import AsyncCallback |
94 | | -from airflow.sdk.definitions.deadline import DeadlineReference |
| 94 | +from airflow.sdk.definitions.deadline import ( |
| 95 | + DAGRUN_CREATED_TIMING, |
| 96 | + DAGRUN_QUEUED_TIMING, |
| 97 | + BaseDeadlineReference, |
| 98 | + DeadlineReference, |
| 99 | +) |
95 | 100 | from airflow.sdk.definitions.param import process_params |
96 | 101 | from airflow.sdk.definitions.taskgroup import TaskGroup |
97 | 102 | from airflow.sdk.execution_time.comms import AssetEventsResult |
98 | 103 | from airflow.serialization.definitions.assets import SerializedAsset |
99 | 104 | from airflow.serialization.definitions.baseoperator import SerializedBaseOperator |
100 | 105 | from airflow.serialization.definitions.dag import SerializedDAG |
101 | | -from airflow.serialization.encoders import ensure_serialized_asset |
| 106 | +from airflow.serialization.encoders import encode_deadline_reference, ensure_serialized_asset |
102 | 107 | from airflow.serialization.serialized_objects import OperatorSerialization, create_scheduler_operator |
103 | 108 | from airflow.ti_deps.dep_context import DepContext |
104 | 109 | from airflow.ti_deps.dependencies_deps import REQUEUEABLE_DEPS, RUNNING_DEPS |
@@ -4190,6 +4195,71 @@ def test_clear_task_instances_recalculates_dagrun_queued_deadlines(dag_maker, se |
4190 | 4195 | assert recalculated_count == 2 |
4191 | 4196 |
|
4192 | 4197 |
|
| 4198 | +@pytest.mark.parametrize( |
| 4199 | + ("timing", "should_recalculate"), |
| 4200 | + [ |
| 4201 | + pytest.param(DAGRUN_QUEUED_TIMING, True, id="queued"), |
| 4202 | + pytest.param(DAGRUN_CREATED_TIMING, False, id="created"), |
| 4203 | + ], |
| 4204 | +) |
| 4205 | +def test_clear_task_instances_recalculates_custom_queued_deadlines( |
| 4206 | + dag_maker, session, timing, should_recalculate |
| 4207 | +): |
| 4208 | + """Test that clearing tasks recalculates custom deadlines registered as queued-anchored.""" |
| 4209 | + |
| 4210 | + class CustomReference(BaseDeadlineReference): |
| 4211 | + evaluation_timing = timing |
| 4212 | + |
| 4213 | + with dag_maker( |
| 4214 | + dag_id="test_recalculate_custom_deadlines", |
| 4215 | + schedule=datetime.timedelta(days=1), |
| 4216 | + ) as dag: |
| 4217 | + EmptyOperator(task_id="task_1") |
| 4218 | + |
| 4219 | + dag_run = dag_maker.create_dagrun() |
| 4220 | + ti = dag_run.get_task_instance("task_1", session=session) |
| 4221 | + ti.set_state(TaskInstanceState.SUCCESS, session=session) |
| 4222 | + |
| 4223 | + original_queued_at = timezone.utcnow() - datetime.timedelta(hours=2) |
| 4224 | + dag_run.queued_at = original_queued_at |
| 4225 | + session.flush() |
| 4226 | + |
| 4227 | + interval = datetime.timedelta(hours=1) |
| 4228 | + deadline_alert = DeadlineAlertModel( |
| 4229 | + serialized_dag_id=session.scalar( |
| 4230 | + select(SerializedDagModel.id).where(SerializedDagModel.dag_id == dag.dag_id) |
| 4231 | + ), |
| 4232 | + reference=encode_deadline_reference(CustomReference()), |
| 4233 | + interval=interval.total_seconds(), |
| 4234 | + callback_def={"path": f"{__name__}.empty_callback_for_deadline", "kwargs": {}}, |
| 4235 | + ) |
| 4236 | + session.add(deadline_alert) |
| 4237 | + session.flush() |
| 4238 | + |
| 4239 | + original_deadline_time = original_queued_at + interval |
| 4240 | + session.add( |
| 4241 | + Deadline( |
| 4242 | + dagrun_id=dag_run.id, |
| 4243 | + deadline_alert_id=deadline_alert.id, |
| 4244 | + deadline_time=original_deadline_time, |
| 4245 | + callback=AsyncCallback(empty_callback_for_deadline), |
| 4246 | + dag_id=dag_run.dag_id, |
| 4247 | + ) |
| 4248 | + ) |
| 4249 | + session.flush() |
| 4250 | + |
| 4251 | + tis = session.scalars(select(TI).where(TI.dag_id == dag.dag_id, TI.run_id == dag_run.run_id)).all() |
| 4252 | + clear_task_instances(tis, session) |
| 4253 | + |
| 4254 | + dag_run = session.scalar(select(DagRun).where(DagRun.id == dag_run.id)) |
| 4255 | + deadline = session.scalar(select(Deadline).where(Deadline.dagrun_id == dag_run.id)) |
| 4256 | + |
| 4257 | + if should_recalculate: |
| 4258 | + assert deadline.deadline_time == dag_run.queued_at + interval |
| 4259 | + else: |
| 4260 | + assert deadline.deadline_time == original_deadline_time |
| 4261 | + |
| 4262 | + |
4193 | 4263 | def test_get_dagrun_loaded_but_none_returns_dagrun(dag_maker, session): |
4194 | 4264 | """ |
4195 | 4265 | Test that `get_dagrun()` fetches `DagRun` from DB when the `dag_run` |
|
0 commit comments