amoghrajesh commented on code in PR #71072:
URL: https://github.com/apache/airflow/pull/71072#discussion_r3966767217


##########
airflow-core/src/airflow/jobs/scheduler_job_runner.py:
##########
@@ -2296,6 +2310,89 @@ def _create_dagruns_for_partitioned_asset_dags(self, 
session: Session) -> set[st
         if not pending_apdrs:
             return set()

Review Comment:
   The only place that resets `self._partition_cap_backlog_reported` to False 
is line 2338-2340, further down, in the branch that runs when 
`len(pending_apdrs) < self._max_partition_dag_runs_per_loop`. That branch never 
runs when the backlog is exactly zero, because the function already returned at 
line 2311.
   
   So here is the failure case: the backlog builds up, hits the cap, and gets 
reported (flag set to True). The backlog then drains all the way to zero in one 
tick, the flag stays True forever because the early return at line 2311 skips 
the reset. Later, a fresh burst of asset events pushes the backlog straight 
back over the cap. The code checks the stale True flag, thinks this is a 
continuation of the old episode, logs at debug instead of warning, and skips 
writing a new audit Log row entirely (the `if not 
self._partition_cap_backlog_reported:` guard at line 2359 is False).
   
   This breaks the one promise this PR makes: "one audit row per backlog 
episode." A brand new episode goes completely unaudited if the backlog happened 
to touch zero first. Reset the flag at the top of the function whenever 
`pending_apdrs` is empty, right next to the early return at line 2310-2311, not 
only in the `len(pending_apdrs) < cap` branch further down.



##########
airflow-core/tests/unit/jobs/test_scheduler_job.py:
##########


Review Comment:
   No test drains the backlog to literally zero and then rebuilds it. Add a 
test that drains the backlog to exactly zero pending APDRs, then adds a fresh 
batch that crosses the cap again, and assert the second episode logs at warning 
and writes a second audit row.



##########
airflow-core/src/airflow/jobs/scheduler_job_runner.py:
##########
@@ -2296,6 +2310,89 @@ def _create_dagruns_for_partitioned_asset_dags(self, 
session: Session) -> set[st
         if not pending_apdrs:
             return set()
 
+        if len(pending_apdrs) >= self._max_partition_dag_runs_per_loop:
+            # A full fetch alone can't tell us whether that's the entire 
backlog or just
+            # this tick's slice of a larger one, so we only pay for this query 
then.
+            # Per-Dag counts across the *whole* backlog, not just this tick's 
oldest-cap
+            # slice (`pending_apdrs`) — a Dag whose partitions haven't reached 
the front of
+            # the FIFO queue yet would otherwise be missing from the log/audit 
row until its
+            # turn comes up.
+            backlogs_per_dag: dict[str, int] = {
+                dag_id: count
+                for dag_id, count in session.execute(
+                    select(AssetPartitionDagRun.target_dag_id, func.count())
+                    .select_from(AssetPartitionDagRun)
+                    .join(DagModel, DagModel.dag_id == 
AssetPartitionDagRun.target_dag_id)
+                    .where(
+                        AssetPartitionDagRun.created_dag_run_id.is_(None),
+                        DagModel.is_stale.is_(False),
+                    )
+                    .group_by(AssetPartitionDagRun.target_dag_id)
+                )
+            }
+            backlog_total = sum(backlogs_per_dag.values())
+            # No SQL-side ORDER BY: it would have no dag_id tie-break, and 
relying on dict
+            # insertion order mirroring DB row order across backends (SQLite 
in tests vs
+            # Postgres/MySQL in production) isn't a contract worth trusting — 
sort explicitly.
+            sorted_dag_ids = sorted(backlogs_per_dag, key=lambda dag_id: 
(-backlogs_per_dag[dag_id], dag_id))
+        else:
+            backlog_total = len(pending_apdrs)
+            self._partition_cap_backlog_reported = False
+
+        if backlog_total > self._max_partition_dag_runs_per_loop:
+            displayed_dag_ids = 
sorted_dag_ids[:MAX_PARTITION_CAP_BACKLOG_DAG_IDS_LOGGED]
+            remaining_dag_id_count = len(sorted_dag_ids) - 
len(displayed_dag_ids)
+            log_cap_reached = self.log.debug if 
self._partition_cap_backlog_reported else self.log.warning

Review Comment:
   `sorted_dag_ids` is set in a conditional statement above and it works fine 
today but it depends on two separate if conditions staying in sync by 
coincidence, not by a name or a comment saying so. A future edit to either 
condition (e.g. changing `>=` to `>`, or changing what backlog_total means in 
the else branch) can turn this into a `NameError`



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to