11from collections .abc import Mapping , Sequence
22from functools import partial
3- from typing import Any , cast
3+ from typing import TYPE_CHECKING , AbstractSet , Any , Union , cast # noqa: UP035
44
55import dagster ._check as check
6- from dagster ._annotations import beta_param , public
6+ from dagster ._annotations import (
7+ beta_param ,
8+ hidden_param ,
9+ only_allow_hidden_params_in_kwargs ,
10+ public ,
11+ )
12+ from dagster ._core .definitions .asset_key import AssetJobKey
713from dagster ._core .definitions .asset_selection import AssetSelection , CoercibleToAssetSelection
814from dagster ._core .definitions .declarative_automation .automation_condition import (
915 AutomationCondition ,
1016)
11- from dagster ._core .definitions .metadata import RawMetadataMapping
17+ from dagster ._core .definitions .metadata import JsonMetadataValue , RawMetadataMapping
1218from dagster ._core .definitions .run_request import SensorResult
1319from dagster ._core .definitions .sensor_definition import (
1420 DefaultSensorStatus ,
2228from dagster ._utils import IHasInternalInit
2329from dagster ._utils .tags import normalize_tags
2430
31+ if TYPE_CHECKING :
32+ from dagster ._core .remote_representation .external_data import SensorMetadataSnap
33+
2534MAX_ENTITIES = 500
2635EMIT_BACKFILLS_METADATA_KEY = "dagster/emit_backfills"
36+ ASSET_JOB_KEYS_METADATA_KEY = "dagster/asset_job_keys"
2737DEFAULT_AUTOMATION_CONDITION_SENSOR_NAME = "default_automation_condition_sensor"
2838
2939
40+ def asset_job_keys_from_sensor_metadata (
41+ metadata : Union [Mapping [str , Any ], "SensorMetadataSnap" , None ],
42+ ) -> AbstractSet [AssetJobKey ]:
43+ """Parses the asset-job keys a sensor is responsible for evaluating out of its metadata.
44+
45+ Accepts two shapes because get_default_automation_condition_sensor_target iterates a
46+ mixed list of sensors: a SensorDefinition's metadata (a normalized
47+ Mapping[str, MetadataValue]) or a RemoteSensor's SensorMetadataSnap. Missing metadata
48+ or a missing key means the sensor claims no job keys; a present key with unexpected
49+ contents is an error.
50+ """
51+ # local import: external_data imports from this module
52+ from dagster ._core .remote_representation .external_data import SensorMetadataSnap
53+
54+ mapping : Mapping [str , Any ] | None = (
55+ metadata .standard_metadata if isinstance (metadata , SensorMetadataSnap ) else metadata
56+ )
57+ if not mapping or ASSET_JOB_KEYS_METADATA_KEY not in mapping :
58+ return set ()
59+ # the sorted list of job names written in __init__ normalizes to a JsonMetadataValue,
60+ # on the definition side and (after the serdes round-trip) on the snapshot side alike
61+ job_names = check .inst (
62+ mapping [ASSET_JOB_KEYS_METADATA_KEY ],
63+ JsonMetadataValue ,
64+ f"unexpected value for sensor metadata key { ASSET_JOB_KEYS_METADATA_KEY } " ,
65+ ).value
66+ return {
67+ AssetJobKey (job_name = check .str_param (job_name , "job_name" )) for job_name in job_names or []
68+ }
69+
70+
3071def _evaluate (sensor_def : "AutomationConditionSensorDefinition" , context : SensorEvaluationContext ):
3172 from dagster ._core .definitions .automation_tick_evaluation_context import (
3273 AutomationTickEvaluationContext ,
@@ -51,6 +92,7 @@ def _evaluate(sensor_def: "AutomationConditionSensorDefinition", context: Sensor
5192 observe_run_tags = {},
5293 auto_observe_asset_keys = set (),
5394 asset_selection = sensor_def .asset_selection ,
95+ asset_job_keys = sensor_def .asset_job_keys ,
5496 emit_backfills = sensor_def .emit_backfills ,
5597 default_condition = sensor_def .default_condition ,
5698 logger = context .log ,
@@ -81,6 +123,13 @@ def not_supported(context) -> None:
81123@public
82124@beta_param (param = "use_user_code_server" )
83125@beta_param (param = "default_condition" )
126+ @hidden_param (
127+ param = "asset_job_keys" ,
128+ breaking_version = "" ,
129+ additional_warn_text = "This parameter is internal: it is populated automatically on the "
130+ "default automation condition sensor and will be replaced by a job-selection API." ,
131+ emit_runtime_warning = False ,
132+ )
84133class AutomationConditionSensorDefinition (SensorDefinition , IHasInternalInit ):
85134 """Targets a set of assets and repeatedly evaluates all the AutomationConditions on all of
86135 those assets to determine which to request runs for.
@@ -159,7 +208,9 @@ def __init__(
159208 emit_backfills : bool = True ,
160209 use_user_code_server : bool = False ,
161210 default_condition : AutomationCondition | None = None ,
211+ ** kwargs : Any ,
162212 ):
213+ only_allow_hidden_params_in_kwargs (AutomationConditionSensorDefinition , kwargs )
163214 self ._use_user_code_server = use_user_code_server
164215 check .bool_param (emit_backfills , "allow_backfills" )
165216
@@ -180,6 +231,20 @@ def __init__(
180231 if emit_backfills :
181232 metadata = {** (metadata or {}), EMIT_BACKFILLS_METADATA_KEY : True }
182233
234+ # asset-job keys are carried in metadata so they cross the snapshot boundary to
235+ # the daemon (the same channel emit_backfills uses)
236+ asset_job_keys = kwargs .get ("asset_job_keys" )
237+ if asset_job_keys :
238+ metadata = {
239+ ** (metadata or {}),
240+ ASSET_JOB_KEYS_METADATA_KEY : sorted (
241+ key .job_name
242+ for key in check .set_param (
243+ asset_job_keys , "asset_job_keys" , of_type = AssetJobKey
244+ )
245+ ),
246+ }
247+
183248 super ().__init__ (
184249 name = check_valid_name (name ),
185250 job_name = None ,
@@ -211,6 +276,11 @@ def emit_backfills(self) -> bool:
211276 def default_condition (self ) -> AutomationCondition | None :
212277 return self ._default_condition
213278
279+ @property
280+ def asset_job_keys (self ) -> AbstractSet [AssetJobKey ]:
281+ """The asset-job entity keys this sensor is responsible for evaluating."""
282+ return asset_job_keys_from_sensor_metadata (self .metadata )
283+
214284 @property
215285 def sensor_type (self ) -> SensorType :
216286 return SensorType .AUTOMATION if self ._use_user_code_server else SensorType .AUTO_MATERIALIZE
@@ -229,6 +299,7 @@ def dagster_internal_init( # type: ignore
229299 emit_backfills : bool ,
230300 use_user_code_server : bool ,
231301 default_condition : AutomationCondition | None ,
302+ ** kwargs : Any ,
232303 ) -> "AutomationConditionSensorDefinition" :
233304 return AutomationConditionSensorDefinition (
234305 name = name ,
@@ -242,6 +313,7 @@ def dagster_internal_init( # type: ignore
242313 emit_backfills = emit_backfills ,
243314 use_user_code_server = use_user_code_server ,
244315 default_condition = default_condition ,
316+ ** kwargs ,
245317 )
246318
247319 def with_attributes (
0 commit comments