11import atexit
2- import gc
32import logging
43import os
54import re
87from collections .abc import Callable
98from typing import TYPE_CHECKING , ClassVar
109from uuid import uuid4
10+ from weakref import WeakSet
1111
1212from datachain .catalog import get_catalog
1313from datachain .data_storage import JobQueryType , JobStatus
@@ -57,6 +57,7 @@ class Session:
5757
5858 GLOBAL_SESSION_CTX : "Session | None" = None
5959 SESSION_CONTEXTS : ClassVar [list ["Session" ]] = []
60+ _ALL_SESSIONS : ClassVar [WeakSet ["Session" ]] = WeakSet ()
6061 ORIGINAL_EXCEPT_HOOK = None
6162
6263 # Job management - class-level to ensure one job per process
@@ -92,6 +93,7 @@ def __init__(
9293 self .catalog = catalog or get_catalog (
9394 client_config = client_config , in_memory = in_memory
9495 )
96+ Session ._ALL_SESSIONS .add (self )
9597
9698 def __enter__ (self ):
9799 # Push the current context onto the stack
@@ -109,6 +111,7 @@ def __exit__(self, exc_type, exc_val, exc_tb):
109111
110112 if Session .SESSION_CONTEXTS :
111113 Session .SESSION_CONTEXTS .pop ()
114+ Session ._ALL_SESSIONS .discard (self )
112115
113116 def get_or_create_job (self ) -> "Job" :
114117 """
@@ -311,6 +314,7 @@ def except_hook(exc_type, exc_value, exc_traceback):
311314
312315 @classmethod
313316 def cleanup_for_tests (cls ):
317+ cls ._close_all_contexts ()
314318 if cls .GLOBAL_SESSION_CTX is not None :
315319 cls .GLOBAL_SESSION_CTX .__exit__ (None , None , None )
316320 cls .GLOBAL_SESSION_CTX = None
@@ -333,15 +337,26 @@ def cleanup_for_tests(cls):
333337
334338 @staticmethod
335339 def _global_cleanup ():
340+ Session ._close_all_contexts ()
336341 if Session .GLOBAL_SESSION_CTX is not None :
337342 Session .GLOBAL_SESSION_CTX .__exit__ (None , None , None )
338343
339- for obj in gc . get_objects (): # Get all tracked objects
344+ for session in list ( Session . _ALL_SESSIONS ):
340345 try :
341- if isinstance (obj , Session ):
342- # Cleanup temp dataset for session variables.
343- obj .__exit__ (None , None , None )
346+ session .__exit__ (None , None , None )
344347 except ReferenceError :
345348 continue # Object has been finalized already
346349 except Exception as e : # noqa: BLE001
347350 logger .error (f"Exception while cleaning up session: { e } " ) # noqa: G004
351+
352+ @classmethod
353+ def _close_all_contexts (cls ) -> None :
354+ while cls .SESSION_CONTEXTS :
355+ session = cls .SESSION_CONTEXTS .pop ()
356+ try :
357+ session .__exit__ (None , None , None )
358+ except Exception as exc : # noqa: BLE001
359+ logger .error (
360+ "Exception while closing session context during cleanup: %s" ,
361+ exc ,
362+ )
0 commit comments