|
1 | 1 | """ChromaDB provisioner implementation.""" |
2 | 2 |
|
3 | 3 | import asyncio |
| 4 | +import os |
| 5 | +import signal |
4 | 6 | import sys |
5 | 7 | import time |
6 | 8 | from typing import Any |
@@ -159,33 +161,24 @@ async def stop(cls, state: dict[str, Any]) -> None: |
159 | 161 |
|
160 | 162 | if pid: |
161 | 163 | try: |
162 | | - # SIGTERM for graceful shutdown (async-safe via subprocess) |
163 | | - proc = await asyncio.create_subprocess_exec( |
164 | | - "kill", |
165 | | - "-TERM", |
166 | | - str(pid), |
167 | | - stdout=asyncio.subprocess.DEVNULL, |
168 | | - stderr=asyncio.subprocess.DEVNULL, |
169 | | - ) |
170 | | - await proc.wait() |
| 164 | + # Graceful shutdown: SIGTERM on Unix, CTRL_BREAK on Windows |
| 165 | + if sys.platform == "win32": |
| 166 | + os.kill(pid, signal.CTRL_BREAK_EVENT) |
| 167 | + else: |
| 168 | + os.kill(pid, signal.SIGTERM) |
171 | 169 |
|
172 | 170 | # Wait for graceful shutdown |
173 | 171 | await asyncio.sleep(2.0) |
174 | 172 |
|
175 | 173 | # Check if still running, force kill if needed |
176 | 174 | if await cls._is_process_running(pid): |
177 | | - kill_proc = await asyncio.create_subprocess_exec( |
178 | | - "kill", |
179 | | - "-KILL", |
180 | | - str(pid), |
181 | | - stdout=asyncio.subprocess.DEVNULL, |
182 | | - stderr=asyncio.subprocess.DEVNULL, |
183 | | - ) |
184 | | - await kill_proc.wait() |
| 175 | + os.kill(pid, signal.SIGKILL if sys.platform != "win32" else signal.SIGTERM) |
185 | 176 | logger.info(f"Force killed ChromaDB process {pid}") |
186 | 177 | else: |
187 | 178 | logger.info(f"ChromaDB process {pid} stopped gracefully") |
188 | 179 |
|
| 180 | + except (OSError, ProcessLookupError): |
| 181 | + logger.info(f"ChromaDB process {pid} already stopped") |
189 | 182 | except Exception as e: |
190 | 183 | logger.warning(f"Error stopping ChromaDB process {pid}: {e}") |
191 | 184 |
|
@@ -237,23 +230,19 @@ async def status(cls, state: dict[str, Any]) -> str: |
237 | 230 |
|
238 | 231 | @classmethod |
239 | 232 | async def _is_process_running(cls, pid: int) -> bool: |
240 | | - """Check if a process is running (async-safe). |
| 233 | + """Check if a process is running. |
241 | 234 |
|
242 | 235 | Args: |
243 | 236 | pid: Process ID to check |
244 | 237 |
|
245 | 238 | Returns: |
246 | 239 | True if process exists, False otherwise |
247 | 240 | """ |
248 | | - proc = await asyncio.create_subprocess_exec( |
249 | | - "kill", |
250 | | - "-0", |
251 | | - str(pid), |
252 | | - stdout=asyncio.subprocess.DEVNULL, |
253 | | - stderr=asyncio.subprocess.DEVNULL, |
254 | | - ) |
255 | | - await proc.wait() |
256 | | - return proc.returncode == 0 |
| 241 | + try: |
| 242 | + os.kill(pid, 0) |
| 243 | + return True |
| 244 | + except (OSError, ProcessLookupError): |
| 245 | + return False |
257 | 246 |
|
258 | 247 | @classmethod |
259 | 248 | async def _wait_for_healthy(cls, http_port: int, timeout: float = 60.0) -> None: |
|
0 commit comments