This is an automated email from the ASF dual-hosted git repository.
ephraimbuddy pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/airflow.git
The following commit(s) were added to refs/heads/main by this push:
new 6761d3bc373 Decouple session ownership and drop unused bundle_version
from parse-result helpers (#66110)
6761d3bc373 is described below
commit 6761d3bc3733deb5da1c7dab94743380b850fc1f
Author: Ephraim Anierobi <[email protected]>
AuthorDate: Thu Apr 30 12:04:00 2026 +0100
Decouple session ownership and drop unused bundle_version from parse-result
helpers (#66110)
The projected AIP-92 DB-to-API swap needs DagFileProcessorManager subclasses
that forward parser results through an API instead of the metadata DB.
``handle_parsing_result`` is already public and the obvious override point,
but its caller ``_collect_results`` is wrapped in ``@provide_session`` and
threads the session in -- so an override that does not need a session has
to either accept and ignore one or replace ``_collect_results`` itself just
to dodge the decorator.
Move the ``@provide_session`` decorator down onto ``handle_parsing_result``
and stop passing the session from ``_collect_results``. The default
behaviour, the persistence path, and the per-cycle error isolation are
unchanged; subclasses overriding ``handle_parsing_result`` can now run
without a session being created on their behalf.
Also drop the unused ``bundle_version`` parameter from
``process_parse_results``
(and its caller / tests) -- it was threaded through but never read.
---
airflow-core/src/airflow/dag_processing/manager.py | 20 +++++++++++++-------
.../tests/unit/dag_processing/test_manager.py | 19 ++++++++++++++++++-
.../tests/unit/dag_processing/test_processor.py | 3 ---
3 files changed, 31 insertions(+), 11 deletions(-)
diff --git a/airflow-core/src/airflow/dag_processing/manager.py
b/airflow-core/src/airflow/dag_processing/manager.py
index 4065baf88b5..747f577e47b 100644
--- a/airflow-core/src/airflow/dag_processing/manager.py
+++ b/airflow-core/src/airflow/dag_processing/manager.py
@@ -1035,8 +1035,13 @@ class DagFileProcessorManager(LoggingMixin):
processor.logger_filehandle.close()
self._file_stats.pop(file, None)
+ @provide_session
def handle_parsing_result(
- self, file: DagFileInfo, proc: DagFileProcessorProcess, *, session:
Session
+ self,
+ file: DagFileInfo,
+ proc: DagFileProcessorProcess,
+ *,
+ session: Session = NEW_SESSION,
) -> None:
"""
Post-process a single finished parse result.
@@ -1046,6 +1051,11 @@ class DagFileProcessorManager(LoggingMixin):
Extracted from ``_collect_results`` to keep result handling and
persistence separate.
+ Owns its own DB session via ``@provide_session`` so subclasses that
+ forward results without touching the metadata DB (e.g. AIP-92
API-backed
+ deployments) can override this method without inheriting a session
+ created by the caller.
+
If persistence fails, the error is logged and the previous persisted
DAG/import-error counts are preserved while a minimal timestamp update
throttles immediate retries, so other files in the same
@@ -1062,7 +1072,6 @@ class DagFileProcessorManager(LoggingMixin):
finish_time=finish_time,
run_count=self._file_stats[file].run_count,
bundle_name=file.bundle_name,
- bundle_version=self._bundle_versions[file.bundle_name],
parsing_result=proc.parsing_result,
is_callback_only=is_callback_only,
relative_fileloc=str(file.rel_path),
@@ -1138,16 +1147,14 @@ class DagFileProcessorManager(LoggingMixin):
files_parsed=files_parsed,
)
- @provide_session
- def _collect_results(self, session: Session = NEW_SESSION):
- # TODO: Use an explicit session in this fn
+ def _collect_results(self):
finished = []
for file, proc in self._processors.items():
if not proc.is_ready:
# This processor hasn't finished yet, or we haven't read all
the output from it yet
continue
finished.append(file)
- self.handle_parsing_result(file, proc, session=session)
+ self.handle_parsing_result(file, proc)
for file in finished:
processor = self._processors.pop(file)
@@ -1482,7 +1489,6 @@ def process_parse_results(
finish_time: datetime,
run_count: int,
bundle_name: str,
- bundle_version: str | None,
parsing_result: DagFileParsingResult | None,
*,
is_callback_only: bool = False,
diff --git a/airflow-core/tests/unit/dag_processing/test_manager.py
b/airflow-core/tests/unit/dag_processing/test_manager.py
index 5b6ff6af014..65558f3b08a 100644
--- a/airflow-core/tests/unit/dag_processing/test_manager.py
+++ b/airflow-core/tests/unit/dag_processing/test_manager.py
@@ -880,6 +880,23 @@ class TestDagFileProcessorManager:
manager._kill_timed_out_processors()
mock_kill.assert_not_called()
+ def
test_handle_parsing_result_provides_its_own_session_when_caller_omits(self):
+ """``handle_parsing_result`` is wrapped in ``@provide_session`` so
subclasses overriding it can run without a caller-supplied session."""
+ manager = DagFileProcessorManager(max_runs=1)
+ file = DagFileInfo(bundle_name="testing", rel_path=Path("abc.txt"),
bundle_path=TEST_DAGS_FOLDER)
+ manager._file_stats[file] = DagFileStat()
+ manager._bundle_versions["testing"] = "v1"
+
+ processor, _ = self.mock_processor(start_time=time.monotonic() - 1)
+ processor.had_callbacks = False
+ processor.parsing_result = DagFileParsingResult(fileloc="abc.txt",
serialized_dags=[])
+
+ with mock.patch.object(manager, "persist_parsing_result") as
mock_persist:
+ manager.handle_parsing_result(file, processor)
+
+ mock_persist.assert_called_once()
+ assert mock_persist.call_args.kwargs["session"] is not None
+
def
test_handle_parsing_result_throttles_retry_when_first_persist_fails(self,
session):
"""Persist errors should throttle retries without claiming persistence
succeeded."""
manager = DagFileProcessorManager(max_runs=1)
@@ -971,7 +988,7 @@ class TestDagFileProcessorManager:
"persist_parsing_result",
side_effect=[RuntimeError("boom"), None],
):
- manager._collect_results(session=session)
+ manager._collect_results()
assert manager._file_stats[file_a] is not stat_a_before
assert manager._file_stats[file_a].num_dags == stat_a_before.num_dags
diff --git a/airflow-core/tests/unit/dag_processing/test_processor.py
b/airflow-core/tests/unit/dag_processing/test_processor.py
index bf07764a83a..e6d16a8708c 100644
--- a/airflow-core/tests/unit/dag_processing/test_processor.py
+++ b/airflow-core/tests/unit/dag_processing/test_processor.py
@@ -660,7 +660,6 @@ def test_callback_processing_does_not_update_timestamps():
finish_time=timezone.utcnow(),
run_count=5,
bundle_name="test",
- bundle_version=None,
parsing_result=None,
is_callback_only=True,
)
@@ -678,7 +677,6 @@ def test_normal_parsing_updates_timestamps():
finish_time=finish_time,
run_count=3,
bundle_name="test-bundle",
- bundle_version="v1",
parsing_result=DagFileParsingResult(fileloc="test.py",
serialized_dags=[]),
is_callback_only=False,
)
@@ -697,7 +695,6 @@ def test_import_error_updates_timestamps():
finish_time=finish_time,
run_count=2,
bundle_name="test-bundle",
- bundle_version="v1",
parsing_result=None,
is_callback_only=False,
)