Skip to content

Commit 29dda21

Browse files
committed
feat(chroma0): add graceful shutdown for bundled chroma server
1 parent 4321055 commit 29dda21

File tree

1 file changed

+15
-4
lines changed

1 file changed

+15
-4
lines changed

src/vectorcode/database/chroma0.py

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import asyncio
2+
import atexit
23
import contextlib
34
import copy
45
import logging
@@ -87,7 +88,7 @@ async def _try_server(base_url: str):
8788
_logger.debug(f"Heartbeat {heartbeat_url} returned {response=}")
8889
if response.status_code == 200:
8990
return True
90-
except (httpx.ConnectError, httpx.ConnectTimeout):
91+
except (httpx.ConnectError, httpx.ConnectTimeout): # pragma: nocover
9192
pass
9293
return False
9394

@@ -100,7 +101,7 @@ async def _wait_for_server(base_url: str, timeout: int = 10):
100101
if await _try_server(base_url):
101102
return
102103

103-
if asyncio.get_event_loop().time() - start_time > timeout:
104+
if asyncio.get_event_loop().time() - start_time > timeout: # pragma: nocover
104105
raise TimeoutError(f"Server did not start within {timeout} seconds.")
105106

106107
await asyncio.sleep(0.1) # Wait before retrying
@@ -163,8 +164,18 @@ def __new__(cls) -> "_Chroma0ClientManager":
163164
if cls.singleton is None:
164165
cls.singleton = super().__new__(cls)
165166
cls.singleton.__clients = {}
167+
168+
atexit.register(cls.singleton._atexit)
169+
166170
return cls.singleton
167171

172+
def _atexit(self):
173+
try:
174+
loop = asyncio.get_running_loop()
175+
except RuntimeError:
176+
loop = asyncio.new_event_loop()
177+
loop.run_until_complete(self.kill_servers())
178+
168179
@contextlib.asynccontextmanager
169180
async def get_client(self, configs: Config, need_lock: bool = True):
170181
project_root = str(expand_path(str(configs.project_root), True))
@@ -198,10 +209,10 @@ async def get_client(self, configs: Config, need_lock: bool = True):
198209
_logger.debug(f"Unlocking {db_log_path}")
199210
await lock.release()
200211

201-
def get_processes(self) -> list[Process]:
212+
def get_processes(self) -> list[Process]: # pragma: nocover
202213
return [i.process for i in self.__clients.values() if i.process is not None]
203214

204-
async def kill_servers(self):
215+
async def kill_servers(self): # pragma: nocover
205216
termination_tasks: list[asyncio.Task] = []
206217
for p in self.get_processes():
207218
_logger.info(f"Killing bundled chroma server with PID: {p.pid}")

0 commit comments

Comments
 (0)