diff --git a/lightrag/api/gunicorn_config.py b/lightrag/api/gunicorn_config.py index f22788a5..7b25b5b9 100644 --- a/lightrag/api/gunicorn_config.py +++ b/lightrag/api/gunicorn_config.py @@ -162,37 +162,3 @@ def post_fork(server, worker): uvicorn_error_logger.handlers = [] uvicorn_error_logger.setLevel(logging.CRITICAL) uvicorn_error_logger.propagate = False - - -def worker_exit(server, worker): - """ - Executed when a worker is about to exit. - - NOTE: When using UvicornWorker (worker_class = "uvicorn.workers.UvicornWorker"), - this hook may NOT be called reliably. UvicornWorker has its own lifecycle - management that prioritizes ASGI lifespan shutdown events. - - The primary cleanup mechanism is handled by: - 1. FastAPI lifespan context manager with GUNICORN_CMD_ARGS check (in lightrag_server.py) - - Workers skip cleanup when GUNICORN_CMD_ARGS is set - 2. on_exit() hook for main process cleanup - - This function serves as a defensive fallback for: - - Non-UvicornWorker scenarios - - Future Gunicorn/Uvicorn behavior changes - - Additional safety layer - - When called, we should only clean up worker-local resources, NOT the shared Manager. - The Manager should only be shut down by the main process in on_exit(). - """ - print("=" * 80) - print(f"GUNICORN WORKER PROCESS: Shutting down worker {worker.pid}") - print(f"Process ID: {os.getpid()}") - print("=" * 80) - - # Clean up worker-local resources without shutting down the Manager - # Pass shutdown_manager=False to prevent Manager shutdown - finalize_share_data(shutdown_manager=False) - - print(f"Worker {worker.pid} cleanup complete") - print("=" * 80) diff --git a/lightrag/api/lightrag_server.py b/lightrag/api/lightrag_server.py index c4f4a3b1..ec8b2f45 100644 --- a/lightrag/api/lightrag_server.py +++ b/lightrag/api/lightrag_server.py @@ -330,7 +330,12 @@ def create_app(args): # Only perform cleanup in Uvicorn single-process mode if "LIGHTRAG_GUNICORN_MODE" not in os.environ: # Clean up shared data + logger.debug("Unvicorn Mode: finalize shared storage...") finalize_share_data() + else: + logger.debug( + "Gunicorn Mode: don not finalize shared storage in worker process" + ) # Initialize FastAPI base_description = ( diff --git a/lightrag/kg/shared_storage.py b/lightrag/kg/shared_storage.py index e7c170d8..c7dc03e5 100644 --- a/lightrag/kg/shared_storage.py +++ b/lightrag/kg/shared_storage.py @@ -10,6 +10,8 @@ from typing import Any, Dict, List, Optional, Union, TypeVar, Generic from lightrag.exceptions import PipelineNotInitializedError +DEBUG_LOCKS = False + # Define a direct print function for critical logs that must be visible in all processes def direct_log(message, enable_output: bool = True, level: str = "DEBUG"): @@ -90,7 +92,6 @@ _storage_keyed_lock: Optional["KeyedUnifiedLock"] = None # async locks for coroutine synchronization in multiprocess mode _async_locks: Optional[Dict[str, asyncio.Lock]] = None -DEBUG_LOCKS = False _debug_n_locks_acquired: int = 0