11import asyncio
2+ from typing import Optional
23
34import graphene
45from dagster ._core .definitions .asset_health .asset_check_health import (
2223 AssetHealthMaterializationMetadata ,
2324 get_materialization_status_and_metadata ,
2425)
26+ from dagster ._core .storage .event_log .base import AssetRecord
2527
2628from dagster_graphql .schema .entity_key import GrapheneAssetKey
2729from dagster_graphql .schema .util import ResolveInfo
@@ -91,11 +93,38 @@ class GrapheneAssetHealthMaterializationDegradedPartitionedMeta(graphene.ObjectT
9193 numFailedPartitions = graphene .NonNull (graphene .Int )
9294 numMissingPartitions = graphene .NonNull (graphene .Int )
9395 totalNumPartitions = graphene .NonNull (graphene .Int )
96+ latestRunId = graphene .String ()
9497 failedRunId = graphene .String ()
9598
9699 class Meta :
97100 name = "AssetHealthMaterializationDegradedPartitionedMeta"
98101
102+ def __init__ (
103+ self ,
104+ asset_key : GrapheneAssetKey ,
105+ num_failed_partitions : int ,
106+ num_missing_partitions : int ,
107+ total_num_partitions : int ,
108+ latest_run_id : str ,
109+ ):
110+ super ().__init__ ()
111+ self ._asset_key = asset_key
112+ self .numFailedPartitions = num_failed_partitions
113+ self .numMissingPartitions = num_missing_partitions
114+ self .totalNumPartitions = total_num_partitions
115+ self .latestRunId = latest_run_id
116+
117+ async def resolve_failedRunId (self , graphene_info : ResolveInfo ) -> Optional [str ]:
118+ # The latest failed run for a degraded partitioned asset may not be the most recent run that
119+ # attempted to materialize the asset. The failed partitions could be in a historical run
120+ asset_record = await AssetRecord .gen (graphene_info .context , self ._asset_key )
121+ if (
122+ asset_record is not None
123+ and asset_record .asset_entry .last_failed_to_materialize_record is not None
124+ ):
125+ return asset_record .asset_entry .last_failed_to_materialize_record .run_id
126+ return None
127+
99128
100129class GrapheneAssetHealthMaterializationHealthyPartitionedMeta (graphene .ObjectType ):
101130 numMissingPartitions = graphene .NonNull (graphene .Int )
@@ -124,6 +153,7 @@ class Meta:
124153
125154 @staticmethod
126155 def from_metadata_class (
156+ asset_key : GrapheneAssetKey ,
127157 metadata : AssetHealthMaterializationMetadata ,
128158 ) -> "GrapheneAssetHealthMaterializationMeta" :
129159 if isinstance (metadata , AssetHealthMaterializationDegradedNotPartitionedMeta ):
@@ -138,10 +168,11 @@ def from_metadata_class(
138168 )
139169 elif isinstance (metadata , AssetHealthMaterializationDegradedPartitionedMeta ):
140170 return GrapheneAssetHealthMaterializationDegradedPartitionedMeta (
141- numFailedPartitions = metadata .num_failed_partitions ,
142- numMissingPartitions = metadata .num_missing_partitions ,
143- totalNumPartitions = metadata .total_num_partitions ,
144- failedRunId = metadata .failed_run_id ,
171+ asset_key = asset_key ,
172+ num_failed_partitions = metadata .num_failed_partitions ,
173+ num_missing_partitions = metadata .num_missing_partitions ,
174+ total_num_partitions = metadata .total_num_partitions ,
175+ latest_run_id = metadata .latest_run_id ,
145176 )
146177 else :
147178 raise ValueError (f"Unknown metadata class: { type (metadata )} " )
@@ -192,7 +223,7 @@ async def resolve_materializationStatusMetadata(
192223 _ , materialization_status_metadata = await self .materialization_status_task
193224 return (
194225 GrapheneAssetHealthMaterializationMeta .from_metadata_class (
195- materialization_status_metadata
226+ asset_key = self . _asset_key , metadata = materialization_status_metadata
196227 )
197228 if materialization_status_metadata
198229 else None
0 commit comments