Skip to content

Commit fe4ff17

Browse files
committed
[ENH] Clean up System instances when clients are destroyed
1 parent 091f8bd commit fe4ff17

File tree

1 file changed

+31
-0
lines changed

1 file changed

+31
-0
lines changed

chromadb/api/shared_system_client.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
class SharedSystemClient:
1111
_identifier_to_system: ClassVar[Dict[str, System]] = {}
12+
_identifier_to_refcount: ClassVar[Dict[str, int]] = {}
1213
_identifier: str
1314

1415
def __init__(
@@ -17,6 +18,9 @@ def __init__(
1718
) -> None:
1819
self._identifier = SharedSystemClient._get_identifier_from_settings(settings)
1920
SharedSystemClient._create_system_if_not_exists(self._identifier, settings)
21+
SharedSystemClient._identifier_to_refcount[self._identifier] = (
22+
SharedSystemClient._identifier_to_refcount.get(self._identifier, 0) + 1
23+
)
2024

2125
@classmethod
2226
def _create_system_if_not_exists(
@@ -25,6 +29,7 @@ def _create_system_if_not_exists(
2529
if identifier not in cls._identifier_to_system:
2630
new_system = System(settings)
2731
cls._identifier_to_system[identifier] = new_system
32+
cls._identifier_to_refcount[identifier] = 0
2833

2934
new_system.instance(ProductTelemetryClient)
3035
new_system.instance(ServerAPI)
@@ -83,9 +88,35 @@ def from_system(cls, system: System) -> "SharedSystemClient":
8388
instance = cls(system.settings)
8489
return instance
8590

91+
def __del__(self) -> None:
92+
"""Clean up System when this client is destroyed."""
93+
if hasattr(self, "_identifier"):
94+
SharedSystemClient._decrement_refcount(self._identifier)
95+
96+
@classmethod
97+
def _decrement_refcount(cls, identifier: str) -> None:
98+
"""Decrement reference count for a System and cleanup if no clients remain."""
99+
if identifier not in cls._identifier_to_refcount:
100+
return
101+
102+
cls._identifier_to_refcount[identifier] -= 1
103+
104+
if cls._identifier_to_refcount[identifier] <= 0:
105+
# since no more client using this system, can stop it and remove from cache
106+
if identifier in cls._identifier_to_system:
107+
system = cls._identifier_to_system[identifier]
108+
system.stop()
109+
del cls._identifier_to_system[identifier]
110+
del cls._identifier_to_refcount[identifier]
111+
86112
@staticmethod
87113
def clear_system_cache() -> None:
114+
"""Clear the system cache so that new systems can be created for an existing path.
115+
This should only be used for testing purposes."""
116+
for system in SharedSystemClient._identifier_to_system.values():
117+
system.stop()
88118
SharedSystemClient._identifier_to_system = {}
119+
SharedSystemClient._identifier_to_refcount = {}
89120

90121
@property
91122
def _system(self) -> System:

0 commit comments

Comments
 (0)