From 2bce943ccad029f6038135835bee8fe83d36b4a0 Mon Sep 17 00:00:00 2001 From: Nataneljpwd Date: Mon, 23 Mar 2026 21:48:58 +0200 Subject: [PATCH 1/6] added new_dagruns_to_examine configuration --- .../src/airflow/config_templates/config.yml | 9 ++++ airflow-core/src/airflow/models/dagrun.py | 53 ++++++++++++++----- 2 files changed, 48 insertions(+), 14 deletions(-) diff --git a/airflow-core/src/airflow/config_templates/config.yml b/airflow-core/src/airflow/config_templates/config.yml index 0c002f5276cfe..a53a751068144 100644 --- a/airflow-core/src/airflow/config_templates/config.yml +++ b/airflow-core/src/airflow/config_templates/config.yml @@ -2519,6 +2519,15 @@ scheduler: type: integer default: "20" see_also: ":ref:`scheduler:ha:tunables`" + max_new_dagruns_per_loop_to_schedule: + description: | + How many NEW dagruns should be scheduled and examined (and locked) when scheduling + and queuing tasks. + Total max_dagruns_per_loop_to_schedule does not change. + example: ~ + version_added: 3.2.1 + type: integer + default: "0" use_job_schedule: description: | Turn off scheduler use of cron intervals by setting this to ``False``. diff --git a/airflow-core/src/airflow/models/dagrun.py b/airflow-core/src/airflow/models/dagrun.py index 73a5a3a875ac7..7772a07c7bd2b 100644 --- a/airflow-core/src/airflow/models/dagrun.py +++ b/airflow-core/src/airflow/models/dagrun.py @@ -605,24 +605,49 @@ def get_running_dag_runs_to_examine(cls, session: Session) -> ScalarResult[DagRu from airflow.models.backfill import BackfillDagRun from airflow.models.dag import DagModel - query = ( - select(cls) - .with_hint(cls, "USE INDEX (idx_dag_run_running_dags)", dialect_name="mysql") - .where(cls.state == DagRunState.RUNNING) - .join(DagModel, DagModel.dag_id == cls.dag_id) - .join(BackfillDagRun, BackfillDagRun.dag_run_id == DagRun.id, isouter=True) - .where( - DagModel.is_paused == false(), - DagModel.is_stale == false(), + def _get_dagrun_query(filters: list[any], order_by: list[any], limit: int): + return ( + select(cls) + .with_hint(cls, "USE INDEX (idx_dag_run_running_dags)", dialect_name="mysql") + .where(cls.state == DagRunState.RUNNING) + .join(DagModel, DagModel.dag_id == cls.dag_id) + .join(BackfillDagRun, BackfillDagRun.dag_run_id == DagRun.id, isouter=True) + .where(*filters) + .order_by(*order_by) + .limit(limit) ) - .order_by( - nulls_first(cast("ColumnElement[Any]", BackfillDagRun.sort_ordinal), session=session), - nulls_first(cast("ColumnElement[Any]", cls.last_scheduling_decision), session=session), - cls.run_after, + + filters = [ + DagModel.is_paused == false(), + DagModel.is_stale == false(), + ] + order = [ + nulls_first(cast("ColumnElement[Any]", BackfillDagRun.sort_ordinal), session=session), + nulls_first(cast("ColumnElement[Any]", cls.last_scheduling_decision), session=session), + cls.run_after, + ] + + new_dagruns_to_examine = airflow_conf.getint("scheduler", "max_new_dagruns_per_loop_to_schedule") + dagruns_to_examine = cls.DEFAULT_DAGRUNS_TO_EXAMINE - new_dagruns_to_examine + + if new_dagruns_to_examine < 0 or new_dagruns_to_examine > cls.DEFAULT_DAGRUNS_TO_EXAMINE: + log.warning( + "'max_new_dagruns_per_loop_to_schedule' is greater or equal to max_dagruns_per_loop_to_schedule or smaller than 0, ignoring configuration" ) - .limit(cls.DEFAULT_DAGRUNS_TO_EXAMINE) + dagruns_to_examine = cls.DEFAULT_DAGRUNS_TO_EXAMINE + new_dagruns_to_examine = 0 + + query = _get_dagrun_query( + filters, + order, + dagruns_to_examine, ) + if new_dagruns_to_examine > 0: + query = query.union( + _get_dagrun_query([*filters, DagRun.last_scheduling_decision.is_not(None)], order, new_dagruns_to_examine) + ) + query = query.where(DagRun.run_after <= func.now()) result = session.scalars(with_row_locks(query, of=cls, session=session, skip_locked=True)).unique() From 03bacfb2cb4aee285af00997006bc30cb9d4a3f3 Mon Sep 17 00:00:00 2001 From: Nataneljpwd Date: Fri, 27 Mar 2026 15:20:26 +0300 Subject: [PATCH 2/6] added an option to choose new dagruns to schedule amount --- .../src/airflow/config_templates/config.yml | 4 +- airflow-core/src/airflow/models/dagrun.py | 71 +++++++---- airflow-core/tests/unit/models/test_dagrun.py | 115 ++++++++++++++++++ 3 files changed, 166 insertions(+), 24 deletions(-) diff --git a/airflow-core/src/airflow/config_templates/config.yml b/airflow-core/src/airflow/config_templates/config.yml index a53a751068144..e999224860205 100644 --- a/airflow-core/src/airflow/config_templates/config.yml +++ b/airflow-core/src/airflow/config_templates/config.yml @@ -2523,7 +2523,9 @@ scheduler: description: | How many NEW dagruns should be scheduled and examined (and locked) when scheduling and queuing tasks. - Total max_dagruns_per_loop_to_schedule does not change. + If set, select `max_dagruns_per_loop_to_schedule` old dagruns (that have been + examined before) + And `max_new_dagruns_per_loop_to_schedule` new dagruns (that have not yet been examined). example: ~ version_added: 3.2.1 type: integer diff --git a/airflow-core/src/airflow/models/dagrun.py b/airflow-core/src/airflow/models/dagrun.py index 7772a07c7bd2b..91f92a9948759 100644 --- a/airflow-core/src/airflow/models/dagrun.py +++ b/airflow-core/src/airflow/models/dagrun.py @@ -49,6 +49,7 @@ not_, or_, text, + union_all, update, ) from sqlalchemy.dialects import postgresql @@ -56,7 +57,16 @@ from sqlalchemy.ext.associationproxy import association_proxy from sqlalchemy.ext.hybrid import hybrid_property from sqlalchemy.ext.mutable import MutableDict -from sqlalchemy.orm import Mapped, declared_attr, joinedload, mapped_column, relationship, synonym, validates +from sqlalchemy.orm import ( + Mapped, + aliased, + declared_attr, + joinedload, + mapped_column, + relationship, + synonym, + validates, +) from sqlalchemy.sql.expression import false, select from sqlalchemy.sql.functions import coalesce @@ -312,6 +322,11 @@ class DagRun(Base, LoggingMixin): "max_dagruns_per_loop_to_schedule", fallback=20, ) + DEFAULT_NEW_DAGRUNS_TO_EXAMINE = airflow_conf.getint( + "scheduler", + "max_new_dagruns_per_loop_to_schedule", + fallback=0, + ) _ti_dag_versions = association_proxy("task_instances", "dag_version") _tih_dag_versions = association_proxy("task_instances_histories", "dag_version") @@ -606,51 +621,61 @@ def get_running_dag_runs_to_examine(cls, session: Session) -> ScalarResult[DagRu from airflow.models.dag import DagModel def _get_dagrun_query(filters: list[any], order_by: list[any], limit: int): - return ( - select(cls) - .with_hint(cls, "USE INDEX (idx_dag_run_running_dags)", dialect_name="mysql") - .where(cls.state == DagRunState.RUNNING) + return select( + select(DagRun) + .with_hint(DagRun, "USE INDEX (idx_dag_run_running_dags)", dialect_name="mysql") + .where(DagRun.state == DagRunState.RUNNING) .join(DagModel, DagModel.dag_id == cls.dag_id) .join(BackfillDagRun, BackfillDagRun.dag_run_id == DagRun.id, isouter=True) .where(*filters) .order_by(*order_by) .limit(limit) + .subquery() ) filters = [ + DagRun.run_after <= func.now(), DagModel.is_paused == false(), DagModel.is_stale == false(), ] + order = [ nulls_first(cast("ColumnElement[Any]", BackfillDagRun.sort_ordinal), session=session), - nulls_first(cast("ColumnElement[Any]", cls.last_scheduling_decision), session=session), - cls.run_after, + nulls_first(cast("ColumnElement[Any]", DagRun.last_scheduling_decision), session=session), + DagRun.run_after, ] - new_dagruns_to_examine = airflow_conf.getint("scheduler", "max_new_dagruns_per_loop_to_schedule") - dagruns_to_examine = cls.DEFAULT_DAGRUNS_TO_EXAMINE - new_dagruns_to_examine + new_dagruns_to_examine = cls.DEFAULT_NEW_DAGRUNS_TO_EXAMINE + dagruns_to_examine = cls.DEFAULT_DAGRUNS_TO_EXAMINE - if new_dagruns_to_examine < 0 or new_dagruns_to_examine > cls.DEFAULT_DAGRUNS_TO_EXAMINE: - log.warning( - "'max_new_dagruns_per_loop_to_schedule' is greater or equal to max_dagruns_per_loop_to_schedule or smaller than 0, ignoring configuration" - ) - dagruns_to_examine = cls.DEFAULT_DAGRUNS_TO_EXAMINE + if new_dagruns_to_examine < 0: + log.warning("'max_new_dagruns_per_loop_to_schedule' is smaller than 0, ignoring configuration") new_dagruns_to_examine = 0 query = _get_dagrun_query( - filters, - order, - dagruns_to_examine, + filters=filters + if new_dagruns_to_examine == 0 + else [*filters, DagRun.last_scheduling_decision.is_not(None)], + order_by=order, + limit=dagruns_to_examine, ) - if new_dagruns_to_examine > 0: - query = query.union( - _get_dagrun_query([*filters, DagRun.last_scheduling_decision.is_not(None)], order, new_dagruns_to_examine) - ) + query = aliased( + DagRun, + union_all( + query, + _get_dagrun_query( + filters=[*filters, DagRun.last_scheduling_decision.is_(None)], + order_by=order, + limit=new_dagruns_to_examine, + ), + ).alias("combined"), + ) - query = query.where(DagRun.run_after <= func.now()) + result = session.scalars( + with_row_locks(select(query), of=cls, session=session, skip_locked=True) + ).unique() - result = session.scalars(with_row_locks(query, of=cls, session=session, skip_locked=True)).unique() return result @classmethod diff --git a/airflow-core/tests/unit/models/test_dagrun.py b/airflow-core/tests/unit/models/test_dagrun.py index 7ad78292a1edd..3842cb4e7cea9 100644 --- a/airflow-core/tests/unit/models/test_dagrun.py +++ b/airflow-core/tests/unit/models/test_dagrun.py @@ -987,6 +987,121 @@ def test_wait_for_downstream(self, dag_maker, session, prev_ti_state, is_ti_sche schedulable_tis = [ti.task_id for ti in decision.schedulable_tis] assert (upstream.task_id in schedulable_tis) == is_ti_schedulable + def test_get_running_dag_runs_ignores_new_dagruns_to_examine_when_smaller_than_0( + self, session, dag_maker + ): + + DagRun.DEFAULT_NEW_DAGRUNS_TO_EXAMINE = 0 + + def create_dagruns( + last_scheduling_decision: datetime.datetime | None = None, + count: int = 20, + ): + dagrun = dag_maker.create_dagrun( + run_type=DagRunType.SCHEDULED, + state=State.RUNNING, + run_after=datetime.datetime(2024, 1, 1), + ) + dagrun.last_scheduling_decision = last_scheduling_decision + session.merge(dagrun) + for _ in range(count - 1): + dagrun = dag_maker.create_dagrun_after( + dagrun, + run_type=DagRunType.SCHEDULED, + state=State.RUNNING, + run_after=datetime.datetime(2024, 1, 1), + ) + + dagrun.last_scheduling_decision = last_scheduling_decision + session.merge(dagrun) + + with dag_maker( + dag_id="dummy_dag", + schedule=datetime.timedelta(days=1), + start_date=datetime.datetime(2024, 1, 1), + session=session, + ): + EmptyOperator(task_id="dummy_task") + + create_dagruns(None, 10) + + with dag_maker( + dag_id="dummy_dag2", + schedule=datetime.timedelta(days=1), + start_date=datetime.datetime(2024, 1, 1), + session=session, + ): + EmptyOperator(task_id="dummy_task2") + + create_dagruns(func.now(), 20) + + session.flush() + + dagruns = list(DagRun.get_running_dag_runs_to_examine(session=session)) + + assert len([dagrun for dagrun in dagruns if dagrun.last_scheduling_decision is None]) == 10 + + assert len([dagrun for dagrun in dagruns if dagrun.last_scheduling_decision is not None]) == 10 + + def test_get_running_dag_runs_with_max_new_dagruns_to_examine(self, session, dag_maker): + + DagRun.DEFAULT_NEW_DAGRUNS_TO_EXAMINE = 10 + + def create_dagruns( + last_scheduling_decision: datetime.datetime | None = None, + count: int = 20, + ): + dagrun = dag_maker.create_dagrun( + run_type=DagRunType.SCHEDULED, + state=State.RUNNING, + run_after=datetime.datetime(2024, 1, 1), + ) + dagrun.last_scheduling_decision = last_scheduling_decision + session.merge(dagrun) + for _ in range(count - 1): + dagrun = dag_maker.create_dagrun_after( + dagrun, + run_type=DagRunType.SCHEDULED, + state=State.RUNNING, + run_after=datetime.datetime(2024, 1, 1), + ) + + dagrun.last_scheduling_decision = last_scheduling_decision + session.merge(dagrun) + + with dag_maker( + dag_id="dummy_dag", + schedule=datetime.timedelta(days=1), + start_date=datetime.datetime(2024, 1, 1), + session=session, + ): + EmptyOperator(task_id="dummy_task") + + create_dagruns(None) + + with dag_maker( + dag_id="dummy_dag2", + schedule=datetime.timedelta(days=1), + start_date=datetime.datetime(2024, 1, 1), + session=session, + ): + EmptyOperator(task_id="dummy_task2") + + create_dagruns(func.now()) + + session.flush() + + dagruns = list(DagRun.get_running_dag_runs_to_examine(session=session)) + + assert ( + len([dagrun for dagrun in dagruns if dagrun.last_scheduling_decision is None]) + == DagRun.DEFAULT_NEW_DAGRUNS_TO_EXAMINE + ) + assert ( + len([dagrun for dagrun in dagruns if dagrun.last_scheduling_decision is not None]) + == DagRun.DEFAULT_DAGRUNS_TO_EXAMINE + ) + @pytest.mark.parametrize("state", [DagRunState.QUEUED, DagRunState.RUNNING]) def test_next_dagruns_to_examine_only_unpaused(self, session, state, testing_dag_bundle): """ From c70108c2cd9855ae241365d6a0dae537b019cb8c Mon Sep 17 00:00:00 2001 From: Nataneljpwd Date: Fri, 27 Mar 2026 16:21:11 +0300 Subject: [PATCH 3/6] separated to 2 queries --- airflow-core/src/airflow/models/dagrun.py | 49 ++++++++++--------- airflow-core/tests/unit/models/test_dagrun.py | 9 +++- 2 files changed, 33 insertions(+), 25 deletions(-) diff --git a/airflow-core/src/airflow/models/dagrun.py b/airflow-core/src/airflow/models/dagrun.py index b2ce93342fd88..5549c25efe3eb 100644 --- a/airflow-core/src/airflow/models/dagrun.py +++ b/airflow-core/src/airflow/models/dagrun.py @@ -49,7 +49,6 @@ not_, or_, text, - union_all, update, ) from sqlalchemy.dialects import postgresql @@ -624,15 +623,18 @@ def get_running_dag_runs_to_examine(cls, session: Session) -> ScalarResult[DagRu def _get_dagrun_query(filters: list[any], order_by: list[any], limit: int): return select( - select(DagRun) - .with_hint(DagRun, "USE INDEX (idx_dag_run_running_dags)", dialect_name="mysql") - .where(DagRun.state == DagRunState.RUNNING) - .join(DagModel, DagModel.dag_id == cls.dag_id) - .join(BackfillDagRun, BackfillDagRun.dag_run_id == DagRun.id, isouter=True) - .where(*filters) - .order_by(*order_by) - .limit(limit) - .subquery() + aliased( + DagRun, + select(DagRun) + .with_hint(DagRun, "USE INDEX (idx_dag_run_running_dags)", dialect_name="mysql") + .where(DagRun.state == DagRunState.RUNNING) + .join(DagModel, DagModel.dag_id == cls.dag_id) + .join(BackfillDagRun, BackfillDagRun.dag_run_id == DagRun.id, isouter=True) + .where(*filters) + .order_by(*order_by) + .limit(limit) + .subquery(), + ), ) filters = [ @@ -662,21 +664,22 @@ def _get_dagrun_query(filters: list[any], order_by: list[any], limit: int): limit=dagruns_to_examine, ) - query = aliased( - DagRun, - union_all( - query, - _get_dagrun_query( - filters=[*filters, DagRun.last_scheduling_decision.is_(None)], - order_by=order, - limit=new_dagruns_to_examine, - ), - ).alias("combined"), + result = ( + session.scalars(with_row_locks(query, of=cls, session=session, skip_locked=True)).unique().all() ) - result = session.scalars( - with_row_locks(select(query), of=cls, session=session, skip_locked=True) - ).unique() + if new_dagruns_to_examine > 0: + new_dagruns_query = _get_dagrun_query( + filters=[*filters, DagRun.last_scheduling_decision.is_(None)], + order_by=order, + limit=new_dagruns_to_examine, + ) + + result = result + ( + session.scalars(with_row_locks(new_dagruns_query, of=cls, session=session, skip_locked=True)) + .unique() + .all() + ) return result diff --git a/airflow-core/tests/unit/models/test_dagrun.py b/airflow-core/tests/unit/models/test_dagrun.py index 8e1623e6606ec..9c5fa1e812005 100644 --- a/airflow-core/tests/unit/models/test_dagrun.py +++ b/airflow-core/tests/unit/models/test_dagrun.py @@ -1146,9 +1146,10 @@ def test_next_dagruns_to_examine_only_unpaused(self, session, state, testing_dag if state == DagRunState.RUNNING: func = DagRun.get_running_dag_runs_to_examine + runs = func(session) else: func = DagRun.get_queued_dag_runs_to_set_running - runs = func(session).all() + runs = func(session).all() assert runs == [dr] @@ -1156,7 +1157,11 @@ def test_next_dagruns_to_examine_only_unpaused(self, session, state, testing_dag session.merge(orm_dag) session.commit() - runs = func(session).all() + if state == DagRunState.RUNNING: + runs = func(session) + else: + runs = func(session).all() + assert runs == [] @mock.patch.object(Stats, "timing") From c5431b90ef43d5196e705c2c2033923f0f157b17 Mon Sep 17 00:00:00 2001 From: Nataneljpwd Date: Fri, 27 Mar 2026 16:33:54 +0300 Subject: [PATCH 4/6] removed subquery --- airflow-core/src/airflow/models/dagrun.py | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/airflow-core/src/airflow/models/dagrun.py b/airflow-core/src/airflow/models/dagrun.py index 5549c25efe3eb..400b692fe0663 100644 --- a/airflow-core/src/airflow/models/dagrun.py +++ b/airflow-core/src/airflow/models/dagrun.py @@ -58,7 +58,6 @@ from sqlalchemy.ext.mutable import MutableDict from sqlalchemy.orm import ( Mapped, - aliased, declared_attr, joinedload, mapped_column, @@ -622,19 +621,15 @@ def get_running_dag_runs_to_examine(cls, session: Session) -> ScalarResult[DagRu from airflow.models.dag import DagModel def _get_dagrun_query(filters: list[any], order_by: list[any], limit: int): - return select( - aliased( - DagRun, - select(DagRun) - .with_hint(DagRun, "USE INDEX (idx_dag_run_running_dags)", dialect_name="mysql") - .where(DagRun.state == DagRunState.RUNNING) - .join(DagModel, DagModel.dag_id == cls.dag_id) - .join(BackfillDagRun, BackfillDagRun.dag_run_id == DagRun.id, isouter=True) - .where(*filters) - .order_by(*order_by) - .limit(limit) - .subquery(), - ), + return ( + select(DagRun) + .with_hint(DagRun, "USE INDEX (idx_dag_run_running_dags)", dialect_name="mysql") + .where(DagRun.state == DagRunState.RUNNING) + .join(DagModel, DagModel.dag_id == cls.dag_id) + .join(BackfillDagRun, BackfillDagRun.dag_run_id == DagRun.id, isouter=True) + .where(*filters) + .order_by(*order_by) + .limit(limit) ) filters = [ From 36e05143d2a67fa56779f28a56164797231986f2 Mon Sep 17 00:00:00 2001 From: Natanel Rudyuklakir Date: Fri, 27 Mar 2026 19:02:46 +0300 Subject: [PATCH 5/6] fixed mypy --- airflow-core/src/airflow/models/dagrun.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/airflow-core/src/airflow/models/dagrun.py b/airflow-core/src/airflow/models/dagrun.py index 400b692fe0663..a642259bb6af4 100644 --- a/airflow-core/src/airflow/models/dagrun.py +++ b/airflow-core/src/airflow/models/dagrun.py @@ -110,7 +110,7 @@ from pydantic import NonNegativeInt from sqlalchemy.engine import ScalarResult from sqlalchemy.orm import Session - from sqlalchemy.sql.elements import Case, ColumnElement + from sqlalchemy.sql.elements import BinaryExpression, Case, ColumnElement from airflow.models.dag_version import DagVersion from airflow.models.taskinstancekey import TaskInstanceKey @@ -607,7 +607,7 @@ def active_runs_of_dags( @classmethod @retry_db_transaction - def get_running_dag_runs_to_examine(cls, session: Session) -> ScalarResult[DagRun]: + def get_running_dag_runs_to_examine(cls, session: Session) -> Sequence[DagRun]: """ Return the next DagRuns that the scheduler should attempt to schedule. @@ -620,7 +620,7 @@ def get_running_dag_runs_to_examine(cls, session: Session) -> ScalarResult[DagRu from airflow.models.backfill import BackfillDagRun from airflow.models.dag import DagModel - def _get_dagrun_query(filters: list[any], order_by: list[any], limit: int): + def _get_dagrun_query(filters: list[BinaryExpression], order_by: list[BinaryExpression], limit: int): return ( select(DagRun) .with_hint(DagRun, "USE INDEX (idx_dag_run_running_dags)", dialect_name="mysql") @@ -659,7 +659,7 @@ def _get_dagrun_query(filters: list[any], order_by: list[any], limit: int): limit=dagruns_to_examine, ) - result = ( + result: Sequence[DagRun] = ( session.scalars(with_row_locks(query, of=cls, session=session, skip_locked=True)).unique().all() ) From 25ced1ce5aa3c42078ef5996cdf77a9079f8f228 Mon Sep 17 00:00:00 2001 From: Natanel Rudyuklakir Date: Fri, 27 Mar 2026 19:15:48 +0300 Subject: [PATCH 6/6] fixed mypy --- airflow-core/src/airflow/models/dagrun.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/airflow-core/src/airflow/models/dagrun.py b/airflow-core/src/airflow/models/dagrun.py index a642259bb6af4..bc88b7894b204 100644 --- a/airflow-core/src/airflow/models/dagrun.py +++ b/airflow-core/src/airflow/models/dagrun.py @@ -39,6 +39,7 @@ Index, Integer, PrimaryKeyConstraint, + SQLColumnExpression, String, Text, UniqueConstraint, @@ -110,7 +111,7 @@ from pydantic import NonNegativeInt from sqlalchemy.engine import ScalarResult from sqlalchemy.orm import Session - from sqlalchemy.sql.elements import BinaryExpression, Case, ColumnElement + from sqlalchemy.sql.elements import Case, ColumnElement from airflow.models.dag_version import DagVersion from airflow.models.taskinstancekey import TaskInstanceKey @@ -620,7 +621,9 @@ def get_running_dag_runs_to_examine(cls, session: Session) -> Sequence[DagRun]: from airflow.models.backfill import BackfillDagRun from airflow.models.dag import DagModel - def _get_dagrun_query(filters: list[BinaryExpression], order_by: list[BinaryExpression], limit: int): + def _get_dagrun_query( + filters: list[ColumnElement[bool]], order_by: list[SQLColumnExpression[Any]], limit: int + ): return ( select(DagRun) .with_hint(DagRun, "USE INDEX (idx_dag_run_running_dags)", dialect_name="mysql") @@ -669,13 +672,14 @@ def _get_dagrun_query(filters: list[BinaryExpression], order_by: list[BinaryExpr order_by=order, limit=new_dagruns_to_examine, ) - - result = result + ( + new_dagruns: Sequence[DagRun] = ( session.scalars(with_row_locks(new_dagruns_query, of=cls, session=session, skip_locked=True)) .unique() .all() ) + result = [*result, *new_dagruns] + return result @classmethod