From 816feefd84629f79e331b070cf7aa1950fa686df Mon Sep 17 00:00:00 2001 From: yangdx Date: Wed, 29 Oct 2025 13:53:46 +0800 Subject: [PATCH] Fix cleanup coordination between Gunicorn and UvicornWorker lifecycles MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit • Document UvicornWorker hook limitations • Add GUNICORN_CMD_ARGS cleanup guard • Prevent double cleanup in workers --- lightrag/api/gunicorn_config.py | 17 +++++++++++++++-- lightrag/api/lightrag_server.py | 8 ++++++-- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/lightrag/api/gunicorn_config.py b/lightrag/api/gunicorn_config.py index a19a0b39..f22788a5 100644 --- a/lightrag/api/gunicorn_config.py +++ b/lightrag/api/gunicorn_config.py @@ -168,8 +168,21 @@ def worker_exit(server, worker): """ Executed when a worker is about to exit. - This is called for each worker process when it exits. We should only - clean up worker-local resources here, NOT the shared Manager. + 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) diff --git a/lightrag/api/lightrag_server.py b/lightrag/api/lightrag_server.py index cee831d0..47513b77 100644 --- a/lightrag/api/lightrag_server.py +++ b/lightrag/api/lightrag_server.py @@ -326,8 +326,12 @@ def create_app(args): # Clean up database connections await rag.finalize_storages() - # Clean up shared data - finalize_share_data() + # In Gunicorn mode with preload_app=True, cleanup is handled by worker_exit/on_exit hooks + # Only perform cleanup in Uvicorn single-process mode + if "GUNICORN_CMD_ARGS" not in os.environ: + + # Clean up shared data + finalize_share_data() # Initialize FastAPI base_description = (