uranusjr commented on code in PR #71074:
URL: https://github.com/apache/airflow/pull/71074#discussion_r3732983553


##########
airflow-core/src/airflow/assets/manager.py:
##########
@@ -754,27 +698,124 @@ def _get_or_create_apdr(
         target_partition_date: datetime | None,
         target_dag: DagModel,
         rollup_fingerprint: dict,
-        asset_id: int,
         session: Session,
     ) -> AssetPartitionDagRun:
         """
         Get or create an APDR.
 
-        If 2 processes invoke this method at the same time using the same 
(target_key, target_dag) pair,
-        they may both check the database and, finding no existing APDR, create 
separate instances.
-        This leads to the unintended outcome of having two APDRs created 
instead of one.
-        To resolve this, we add a mutex lock to AssetModel for PostgreSQL and 
MySQL and use
-        AssetPartitionDagRunMutexLock table for SQLite.
+        If 2 processes invoke this method at the same time using the same 
(target_key, target_dag)
+        pair, they may both check the database and, finding no existing APDR, 
attempt to create
+        separate instances. Rather than serializing this find-or-create behind 
a lock, a unique
+        constraint on (target_dag_id, pending_partition_key) — see the 
``AssetPartitionDagRun``
+        docstring — makes the database itself reject the loser's INSERT. The 
loser catches that
+        ``IntegrityError`` and re-selects, working on the winning row instead 
of raising, per the
+        model's "always work on the latest matching APDR record" contract. 
Optimistic and
+        lock-free, this scales with concurrent producer assets without 
contending on a Dag or
+        Asset row that has nothing to do with the (target_key, target_dag) 
pair being deduplicated.
 
         ``rollup_fingerprint`` is the serialized mapper / window definition 
for all partitioned
         assets in the timetable at creation time; the scheduler discards APDRs 
whose stamp no
         longer matches the current timetable's fingerprint (mapper / window 
may have changed).
+        """
+        latest_apdr = cls._get_latest_pending_apdr(
+            target_key=target_key, target_dag_id=target_dag.dag_id, 
session=session
+        )
+        if latest_apdr is not None:
+            cls._reconcile_partition_date(
+                apdr=latest_apdr,
+                target_partition_date=target_partition_date,
+                target_dag_id=target_dag.dag_id,
+                target_key=target_key,
+                session=session,
+            )
+            cls.logger().debug(
+                "Existing APDR found for key %s dag_id %s",
+                target_key,
+                target_dag.dag_id,
+                exc_info=True,
+            )
+            return latest_apdr
+
+        apdr = AssetPartitionDagRun(
+            target_dag_id=target_dag.dag_id,
+            created_dag_run_id=None,
+            partition_key=target_key,
+            pending_partition_key=target_key,
+            partition_date=target_partition_date,
+            rollup_fingerprint=rollup_fingerprint,
+        )
+        try:
+            # A SAVEPOINT scopes the potential IntegrityError so only this 
INSERT is rolled
+            # back on conflict; the caller's surrounding transaction (with any 
other work
+            # already flushed in this scheduler tick) stays intact.
+            with session.begin_nested():
+                session.add(apdr)
+                session.flush()

Review Comment:
   SQLAlchemy's savepoint rollback expunges all of session._new, not just what 
was added inside. `_queue_partitioned_dags` accumulates unflushed 
PartitionedAssetKeyLog and Log rows across loop iterations. Losing a log row 
reproduces the same "APDR never satisfied" failure this PR fixes.



-- 
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