@@ -887,12 +887,12 @@ def _has_environment_changed() -> bool:
887887 return completion_status
888888
889889 @python_api_analytics
890- def run_janitor (self , ignore_ttl : bool ) -> bool :
890+ def run_janitor (self , ignore_ttl : bool , force_delete : bool = False ) -> bool :
891891 success = False
892892
893893 if self .console .start_cleanup (ignore_ttl ):
894894 try :
895- self ._run_janitor (ignore_ttl )
895+ self ._run_janitor (ignore_ttl , force_delete = force_delete )
896896 success = True
897897 finally :
898898 self .console .stop_cleanup (success = success )
@@ -2896,24 +2896,43 @@ def _destroy(self) -> bool:
28962896
28972897 return True
28982898
2899- def _run_janitor (self , ignore_ttl : bool = False ) -> None :
2899+ def _run_janitor (self , ignore_ttl : bool = False , force_delete : bool = False ) -> None :
29002900 current_ts = now_timestamp ()
2901+ failures : t .List [str ] = []
29012902
29022903 # Clean up expired environments by removing their views and schemas
2903- self ._cleanup_environments (current_ts = current_ts )
2904+ failures .extend (
2905+ self ._cleanup_environments (current_ts = current_ts , force_delete = force_delete )
2906+ )
29042907
2905- delete_expired_snapshots (
2906- self .state_sync ,
2907- self .snapshot_evaluator ,
2908- current_ts = current_ts ,
2909- ignore_ttl = ignore_ttl ,
2910- console = self .console ,
2911- batch_size = self .config .janitor .expired_snapshots_batch_size ,
2908+ failures .extend (
2909+ delete_expired_snapshots (
2910+ self .state_sync ,
2911+ self .snapshot_evaluator ,
2912+ current_ts = current_ts ,
2913+ ignore_ttl = ignore_ttl ,
2914+ force_delete = force_delete ,
2915+ console = self .console ,
2916+ batch_size = self .config .janitor .expired_snapshots_batch_size ,
2917+ )
29122918 )
29132919 self .state_sync .compact_intervals ()
29142920
2915- def _cleanup_environments (self , current_ts : t .Optional [int ] = None ) -> None :
2921+ if failures :
2922+ failure_string = "\n - " .join (failures )
2923+ summary = f"Janitor completed with failures:\n { failure_string } "
2924+ if force_delete :
2925+ summary += "\n State records have been deleted, but the underlying objects may still exist in the database.\n Please investigate and clean up manually the above if necessary."
2926+ if self .config .janitor .warn_on_delete_failure :
2927+ self .console .log_warning (summary )
2928+ else :
2929+ raise SQLMeshError (summary )
2930+
2931+ def _cleanup_environments (
2932+ self , current_ts : t .Optional [int ] = None , force_delete : bool = False
2933+ ) -> t .List [str ]:
29162934 current_ts = current_ts or now_timestamp ()
2935+ failures : t .List [str ] = []
29172936
29182937 expired_environments_summaries = self .state_sync .get_expired_environments (
29192938 current_ts = current_ts
@@ -2923,15 +2942,20 @@ def _cleanup_environments(self, current_ts: t.Optional[int] = None) -> None:
29232942 expired_env = self .state_reader .get_environment (expired_env_summary .name )
29242943
29252944 if expired_env :
2926- cleanup_expired_views (
2927- default_adapter = self .engine_adapter ,
2928- engine_adapters = self .engine_adapters ,
2929- environments = [expired_env ],
2930- warn_on_delete_failure = self .config .janitor .warn_on_delete_failure ,
2931- console = self .console ,
2945+ failures .extend (
2946+ cleanup_expired_views (
2947+ default_adapter = self .engine_adapter ,
2948+ engine_adapters = self .engine_adapters ,
2949+ environments = [expired_env ],
2950+ console = self .console ,
2951+ )
29322952 )
29332953
2934- self .state_sync .delete_expired_environments (current_ts = current_ts )
2954+ # we want to retry on the next janitor pass if drops failed, unless
2955+ # force_delete is set in which case we purge state records regardless
2956+ if not failures or force_delete :
2957+ self .state_sync .delete_expired_environments (current_ts = current_ts )
2958+ return failures
29352959
29362960 def _try_connection (self , connection_name : str , validator : t .Callable [[], None ]) -> None :
29372961 connection_name = connection_name .capitalize ()
0 commit comments