116116 run_tests ,
117117)
118118from sqlmesh .core .user import User
119- from sqlmesh .utils import UniqueKeyDict , Verbosity
119+ from sqlmesh .utils import UniqueKeyDict , Verbosity , CorrelationId
120120from sqlmesh .utils .concurrency import concurrent_apply_to_values
121121from sqlmesh .utils .dag import DAG
122122from sqlmesh .utils .date import (
@@ -418,7 +418,7 @@ def __init__(
418418 self .config .get_state_connection (self .gateway ) or self .connection_config
419419 )
420420
421- self ._snapshot_evaluator : t .Optional [SnapshotEvaluator ] = None
421+ self ._snapshot_evaluators : t .Dict [ t . Optional [CorrelationId ], SnapshotEvaluator ] = {}
422422
423423 self .console = get_console ()
424424 setattr (self .console , "dialect" , self .config .dialect )
@@ -446,18 +446,22 @@ def engine_adapter(self) -> EngineAdapter:
446446 self ._engine_adapter = self .connection_config .create_engine_adapter ()
447447 return self ._engine_adapter
448448
449- @property
450- def snapshot_evaluator (self ) -> SnapshotEvaluator :
451- if not self ._snapshot_evaluator :
452- self ._snapshot_evaluator = SnapshotEvaluator (
449+ def snapshot_evaluator (
450+ self , correlation_id : t .Optional [CorrelationId ] = None
451+ ) -> SnapshotEvaluator :
452+ # Cache snapshot evaluators by correlation_id to avoid old correlation_ids being attached to future Context operations
453+ if correlation_id not in self ._snapshot_evaluators :
454+ self ._snapshot_evaluators [correlation_id ] = SnapshotEvaluator (
453455 {
454- gateway : adapter .with_log_level (logging .INFO )
456+ gateway : adapter .with_settings (
457+ log_level = logging .INFO , correlation_id = correlation_id
458+ )
455459 for gateway , adapter in self .engine_adapters .items ()
456460 },
457461 ddl_concurrent_tasks = self .concurrent_tasks ,
458462 selected_gateway = self .selected_gateway ,
459463 )
460- return self ._snapshot_evaluator
464+ return self ._snapshot_evaluators [ correlation_id ]
461465
462466 def execution_context (
463467 self ,
@@ -538,7 +542,9 @@ def scheduler(self, environment: t.Optional[str] = None) -> Scheduler:
538542
539543 return self .create_scheduler (snapshots )
540544
541- def create_scheduler (self , snapshots : t .Iterable [Snapshot ]) -> Scheduler :
545+ def create_scheduler (
546+ self , snapshots : t .Iterable [Snapshot ], correlation_id : t .Optional [CorrelationId ] = None
547+ ) -> Scheduler :
542548 """Creates the built-in scheduler.
543549
544550 Args:
@@ -549,7 +555,7 @@ def create_scheduler(self, snapshots: t.Iterable[Snapshot]) -> Scheduler:
549555 """
550556 return Scheduler (
551557 snapshots ,
552- self .snapshot_evaluator ,
558+ self .snapshot_evaluator ( correlation_id ) ,
553559 self .state_sync ,
554560 default_catalog = self .default_catalog ,
555561 max_workers = self .concurrent_tasks ,
@@ -714,7 +720,7 @@ def run(
714720 NotificationEvent .RUN_START , environment = environment
715721 )
716722 analytics_run_id = analytics .collector .on_run_start (
717- engine_type = self .snapshot_evaluator .adapter .dialect ,
723+ engine_type = self .snapshot_evaluator () .adapter .dialect ,
718724 state_sync_type = self .state_sync .state_type (),
719725 )
720726 self ._load_materializations ()
@@ -1076,7 +1082,7 @@ def evaluate(
10761082 and not parent_snapshot .categorized
10771083 ]
10781084
1079- df = self .snapshot_evaluator .evaluate_and_fetch (
1085+ df = self .snapshot_evaluator () .evaluate_and_fetch (
10801086 snapshot ,
10811087 start = start ,
10821088 end = end ,
@@ -1588,7 +1594,12 @@ def apply(
15881594 default_catalog = self .default_catalog ,
15891595 console = self .console ,
15901596 )
1591- explainer .evaluate (plan .to_evaluatable ())
1597+ explainer .evaluate (
1598+ plan .to_evaluatable (),
1599+ snapshot_evaluator = self .snapshot_evaluator (
1600+ correlation_id = CorrelationId .from_plan_id (plan .plan_id )
1601+ ),
1602+ )
15921603 return
15931604
15941605 self .notification_target_manager .notify (
@@ -1902,7 +1913,7 @@ def _table_diff(
19021913 )
19031914
19041915 return TableDiff (
1905- adapter = adapter .with_log_level (logger .getEffectiveLevel ()),
1916+ adapter = adapter .with_settings (logger .getEffectiveLevel ()),
19061917 source = source ,
19071918 target = target ,
19081919 on = on ,
@@ -2111,7 +2122,7 @@ def audit(
21112122 errors = []
21122123 skipped_count = 0
21132124 for snapshot in snapshots :
2114- for audit_result in self .snapshot_evaluator .audit (
2125+ for audit_result in self .snapshot_evaluator () .audit (
21152126 snapshot = snapshot ,
21162127 start = start ,
21172128 end = end ,
@@ -2143,7 +2154,7 @@ def audit(
21432154 self .console .log_status_update (f"Got { error .count } results, expected 0." )
21442155 if error .query :
21452156 self .console .show_sql (
2146- f"{ error .query .sql (dialect = self .snapshot_evaluator .adapter .dialect )} "
2157+ f"{ error .query .sql (dialect = self .snapshot_evaluator () .adapter .dialect )} "
21472158 )
21482159
21492160 self .console .log_status_update ("Done." )
@@ -2335,11 +2346,14 @@ def print_environment_names(self) -> None:
23352346
23362347 def close (self ) -> None :
23372348 """Releases all resources allocated by this context."""
2338- if self ._snapshot_evaluator :
2339- self ._snapshot_evaluator .close ()
2349+ for evaluator in self ._snapshot_evaluators .values ():
2350+ evaluator .close ()
2351+
23402352 if self ._state_sync :
23412353 self ._state_sync .close ()
23422354
2355+ self ._snapshot_evaluators .clear ()
2356+
23432357 def _run (
23442358 self ,
23452359 environment : str ,
@@ -2390,7 +2404,11 @@ def _run(
23902404
23912405 def _apply (self , plan : Plan , circuit_breaker : t .Optional [t .Callable [[], bool ]]) -> None :
23922406 self ._scheduler .create_plan_evaluator (self ).evaluate (
2393- plan .to_evaluatable (), circuit_breaker = circuit_breaker
2407+ plan .to_evaluatable (),
2408+ snapshot_evaluator = self .snapshot_evaluator (
2409+ correlation_id = CorrelationId .from_plan_id (plan .plan_id )
2410+ ),
2411+ circuit_breaker = circuit_breaker ,
23942412 )
23952413
23962414 @python_api_analytics
@@ -2683,7 +2701,7 @@ def _run_janitor(self, ignore_ttl: bool = False) -> None:
26832701 )
26842702
26852703 # Remove the expired snapshots tables
2686- self .snapshot_evaluator .cleanup (
2704+ self .snapshot_evaluator () .cleanup (
26872705 target_snapshots = cleanup_targets ,
26882706 on_complete = self .console .update_cleanup_progress ,
26892707 )
0 commit comments