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

uranusjr pushed a commit to branch v2-11-test
in repository https://gitbox.apache.org/repos/asf/airflow.git


The following commit(s) were added to refs/heads/v2-11-test by this push:
     new 5bb98e026e8 Consider stale dags when processing dataset events (#64521)
5bb98e026e8 is described below

commit 5bb98e026e8b51cb131ae5c3002818bd11a99b44
Author: Tzu-ping Chung <[email protected]>
AuthorDate: Wed Apr 22 17:18:36 2026 +0800

    Consider stale dags when processing dataset events (#64521)
---
 airflow/datasets/manager.py              |  6 ++---
 tests/datasets/test_manager.py           | 43 ++++++++++++++++++++++++++++----
 tests/jobs/test_scheduler_job.py         |  5 +++-
 tests/listeners/test_dataset_listener.py |  8 ++++++
 4 files changed, 52 insertions(+), 10 deletions(-)

diff --git a/airflow/datasets/manager.py b/airflow/datasets/manager.py
index 306781daba2..230dc55d18d 100644
--- a/airflow/datasets/manager.py
+++ b/airflow/datasets/manager.py
@@ -114,7 +114,7 @@ class DatasetManager(LoggingMixin):
         session.add(dataset_event)
 
         dags_to_queue_from_dataset = {
-            ref.dag for ref in dataset_model.consuming_dags if 
ref.dag.is_active and not ref.dag.is_paused
+            ref.dag for ref in dataset_model.consuming_dags if not 
ref.dag.is_paused
         }
         dags_to_queue_from_dataset_alias = set()
         if source_alias_names:
@@ -133,9 +133,7 @@ class DatasetManager(LoggingMixin):
                 session.add(dsa)
 
                 dags_to_queue_from_dataset_alias |= {
-                    alias_ref.dag
-                    for alias_ref in dsa.consuming_dags
-                    if alias_ref.dag.is_active and not alias_ref.dag.is_paused
+                    alias_ref.dag for alias_ref in dsa.consuming_dags if not 
alias_ref.dag.is_paused
                 }
 
         dags_to_reparse = dags_to_queue_from_dataset_alias - 
dags_to_queue_from_dataset
diff --git a/tests/datasets/test_manager.py b/tests/datasets/test_manager.py
index cf36c8a8e3a..9eb98734faf 100644
--- a/tests/datasets/test_manager.py
+++ b/tests/datasets/test_manager.py
@@ -22,7 +22,7 @@ from datetime import datetime
 from unittest import mock
 
 import pytest
-from sqlalchemy import delete
+from sqlalchemy import delete, func, select
 
 from airflow.datasets import Dataset, DatasetAlias
 from airflow.datasets.manager import DatasetManager
@@ -46,7 +46,7 @@ pytestmark = pytest.mark.db_test
 pytest.importorskip("pydantic", minversion="2.0.0")
 
 
[email protected]
[email protected](autouse=True)
 def clear_datasets():
     from tests.test_utils.db import clear_db_datasets
 
@@ -55,6 +55,13 @@ def clear_datasets():
     clear_db_datasets()
 
 
[email protected](autouse=True)
+def clean_listener_manager():
+    dataset_listener.clear()
+    yield
+    dataset_listener.clear()
+
+
 @pytest.fixture
 def mock_task_instance():
     return TaskInstancePydantic(
@@ -145,7 +152,6 @@ class TestDatasetManager:
         assert session.query(DatasetDagRunQueue).count() == 2
 
     @pytest.mark.skip_if_database_isolation_mode
-    @pytest.mark.usefixtures("clear_datasets")
     def test_register_dataset_change_with_alias(self, session, dag_maker, 
mock_task_instance):
         consumer_dag_1 = DagModel(dag_id="conumser_1", is_active=True, 
fileloc="dag1.py")
         consumer_dag_2 = DagModel(dag_id="conumser_2", is_active=True, 
fileloc="dag2.py")
@@ -197,7 +203,6 @@ class TestDatasetManager:
     @pytest.mark.skip_if_database_isolation_mode
     def test_register_dataset_change_notifies_dataset_listener(self, session, 
mock_task_instance):
         dsem = DatasetManager()
-        dataset_listener.clear()
         get_listener_manager().add_listener(dataset_listener)
 
         ds = Dataset(uri="test_dataset_uri_2")
@@ -218,7 +223,6 @@ class TestDatasetManager:
     @pytest.mark.skip_if_database_isolation_mode
     def test_create_datasets_notifies_dataset_listener(self, session):
         dsem = DatasetManager()
-        dataset_listener.clear()
         get_listener_manager().add_listener(dataset_listener)
 
         dsm = DatasetModel(uri="test_dataset_uri_3")
@@ -228,3 +232,32 @@ class TestDatasetManager:
         # Ensure the listener was notified
         assert len(dataset_listener.created) == 1
         assert dataset_listener.created[0].uri == dsm.uri
+
+    @pytest.mark.skip_if_database_isolation_mode
+    def test_register_dataset_change_queues_stale_dag(self, session, 
mock_task_instance):
+        dsem = DatasetManager()
+
+        dsm = DatasetModel(uri="test_dataset_uri_3")
+        session.add(dsm)
+
+        # Setup a dag that is STALE but NOT PAUSED
+        # We want stale dags to still receive updates
+        stale_dag = DagModel(dag_id="stale_dag", is_active=False, 
is_paused=False)
+        session.add(stale_dag)
+
+        # Link stale dags to the dataset
+        dsm.consuming_dags = 
[DagScheduleDatasetReference(dag_id=stale_dag.dag_id)]
+
+        session.execute(delete(DatasetDagRunQueue))
+        session.flush()
+
+        dsem.register_dataset_change(
+            task_instance=mock_task_instance,
+            dataset=Dataset(dsm.uri),
+            session=session,
+        )
+        session.flush()
+
+        # Verify the stale Dag was NOT ignored
+        assert 
session.scalar(select(func.count()).select_from(DatasetDagRunQueue)) == 1
+        assert session.scalar(select(DatasetDagRunQueue.target_dag_id)) == 
"stale_dag"
diff --git a/tests/jobs/test_scheduler_job.py b/tests/jobs/test_scheduler_job.py
index abf394743ee..e034e4d401b 100644
--- a/tests/jobs/test_scheduler_job.py
+++ b/tests/jobs/test_scheduler_job.py
@@ -4479,7 +4479,10 @@ class TestSchedulerJob:
             session=session,
         )
         assert session.scalars(dse_q).one().source_run_id == dr1.run_id
-        assert session.scalars(ddrq_q).one_or_none() is None
+        if "is_active" in disable:
+            assert session.scalars(ddrq_q).one_or_none() is not None
+        else:
+            assert session.scalars(ddrq_q).one_or_none() is None
 
         # Simulate the consumer DAG being enabled.
         session.execute(update(DagModel).where(DagModel.dag_id == 
"consumer").values(**enable))
diff --git a/tests/listeners/test_dataset_listener.py 
b/tests/listeners/test_dataset_listener.py
index b0ac6223e79..2e9669d836d 100644
--- a/tests/listeners/test_dataset_listener.py
+++ b/tests/listeners/test_dataset_listener.py
@@ -24,6 +24,7 @@ from airflow.models.dataset import DatasetModel
 from airflow.operators.empty import EmptyOperator
 from airflow.utils.session import provide_session
 from tests.listeners import dataset_listener
+from tests.test_utils.db import clear_db_datasets
 
 
 @pytest.fixture(autouse=True)
@@ -37,6 +38,13 @@ def clean_listener_manager():
     dataset_listener.clear()
 
 
[email protected](autouse=True)
+def clear_datasets():
+    clear_db_datasets()
+    yield
+    clear_db_datasets()
+
+
 @pytest.mark.skip_if_database_isolation_mode  # Test is broken in db isolation 
mode
 @pytest.mark.db_test
 @provide_session

Reply via email to