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

pierrejeambrun pushed a commit to branch v3-3-test
in repository https://gitbox.apache.org/repos/asf/airflow.git


The following commit(s) were added to refs/heads/v3-3-test by this push:
     new 1fce547150f Activate assets materialized from an AssetAlias so they 
appear in the Assets tab (#71555) (#71935)
1fce547150f is described below

commit 1fce547150f703f67d63efa714f7541481234c78
Author: Pierre Jeambrun <[email protected]>
AuthorDate: Fri Aug 21 14:13:55 2026 +0200

    Activate assets materialized from an AssetAlias so they appear in the 
Assets tab (#71555) (#71935)
    
    An asset created at runtime by attaching it to an AssetAlias outlet via 
Metadata is
    referenced only through the alias association, not the 
schedule/outlet/inlet tables,
    so the asset-orphanage pass treated it as orphaned and never activated it. 
The Assets
    tab defaults to only_active, so the asset (and its alias) never showed up 
despite
    having events. Count the alias association as a reference so such assets 
are activated
    like any other.
    
    Fixes #58058.
    
    (cherry picked from commit 32f8527be1bf032b607e78de5a446d7135f2f2b4)
---
 .../src/airflow/jobs/scheduler_job_runner.py       | 10 ++++++--
 airflow-core/tests/unit/jobs/test_scheduler_job.py | 29 ++++++++++++++++++++++
 2 files changed, 37 insertions(+), 2 deletions(-)

diff --git a/airflow-core/src/airflow/jobs/scheduler_job_runner.py 
b/airflow-core/src/airflow/jobs/scheduler_job_runner.py
index d03b1d456f4..fcc4dfbe335 100644
--- a/airflow-core/src/airflow/jobs/scheduler_job_runner.py
+++ b/airflow-core/src/airflow/jobs/scheduler_job_runner.py
@@ -85,6 +85,7 @@ from airflow.models.asset import (
     PartitionedAssetKeyLog,
     TaskInletAssetReference,
     TaskOutletAssetReference,
+    alias_association_table,
 )
 from airflow.models.asset_state_store import AssetStateStoreModel
 from airflow.models.backfill import Backfill, BackfillDagRun
@@ -3690,8 +3691,8 @@ class SchedulerJobRunner(BaseJobRunner, LoggingMixin):
         Check assets orphanization and update their active entry.
 
         An orphaned asset is no longer referenced in any DAG schedule 
parameters,
-        task outlets, or task inlets. Active assets (non-orphaned) have 
entries in
-        AssetActive and must have unique names and URIs.
+        task outlets, task inlets, or alias associations. Active assets 
(non-orphaned)
+        have entries in AssetActive and must have unique names and URIs.
 
         :seealso: :meth:`AssetModelOperation.activate_assets_if_possible`.
         """
@@ -3701,6 +3702,10 @@ class SchedulerJobRunner(BaseJobRunner, LoggingMixin):
                 func.count(DagScheduleAssetReference.dag_id)
                 + func.count(TaskOutletAssetReference.dag_id)
                 + func.count(TaskInletAssetReference.dag_id)
+                # An asset materialized from an ``AssetAlias`` outlet is 
referenced only through
+                # the alias association, not the schedule/outlet/inlet tables. 
Count it so it is
+                # activated (and shown in the UI) instead of being treated as 
orphaned. See #58058.
+                + func.count(alias_association_table.c.alias_id)
             )
             == 0
         ).label("orphaned")
@@ -3709,6 +3714,7 @@ class SchedulerJobRunner(BaseJobRunner, LoggingMixin):
             .outerjoin(DagScheduleAssetReference)
             .outerjoin(TaskOutletAssetReference)
             .outerjoin(TaskInletAssetReference)
+            .outerjoin(alias_association_table, 
alias_association_table.c.asset_id == AssetModel.id)
             .group_by(AssetModel.id)
         )
 
diff --git a/airflow-core/tests/unit/jobs/test_scheduler_job.py 
b/airflow-core/tests/unit/jobs/test_scheduler_job.py
index 419b459bc36..298a57bd3c6 100644
--- a/airflow-core/tests/unit/jobs/test_scheduler_job.py
+++ b/airflow-core/tests/unit/jobs/test_scheduler_job.py
@@ -8421,6 +8421,35 @@ class TestSchedulerJob:
         assert active == [asset1, asset3, asset5]
         assert orphaned == [asset2, asset4]
 
+    def test_asset_orphaning_keeps_alias_materialized_asset_active(self, 
session):
+        """An asset linked only through an ``AssetAlias`` association must 
stay active, not orphaned.
+
+        Reproduces #58058: a task with an ``AssetAlias`` outlet materializes a 
concrete asset at
+        runtime (via ``Metadata``). It has no schedule/outlet/inlet reference 
— only the alias
+        association — so the orphanage pass used to treat it as orphaned, 
leaving it out of the
+        Assets tab despite having events and a live alias.
+        """
+        self.job_runner = SchedulerJobRunner(job=Job())
+
+        asset = AssetModel(uri="test://alias_materialized", 
name="alias_materialized_asset", group="asset")
+        alias = AssetAliasModel(name="materializing_alias", group="asset")
+        asset.aliases.append(alias)
+        session.add_all([asset, alias])
+        session.flush()
+
+        # Referenced only via the alias association, so inactive before the 
pass.
+        orphaned, active = self._find_assets_activation(session)
+        assert asset in orphaned
+        assert asset not in active
+
+        self.job_runner._update_asset_orphanage(session=session)
+        session.flush()
+
+        # The alias association now counts as a reference, so the asset is 
activated.
+        orphaned, active = self._find_assets_activation(session)
+        assert asset in active
+        assert asset not in orphaned
+
     def test_asset_orphaning_ignore_orphaned_assets(self, dag_maker, session):
         self.job_runner = SchedulerJobRunner(job=Job())
 

Reply via email to