From 3f309105b0a498f4cb7b2f3eac4ae6ec807a55c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20MANSUY?= Date: Thu, 4 Dec 2025 19:18:40 +0800 Subject: [PATCH] cherry-pick d5bcd14c --- lightrag-api | 4 ---- lightrag.service.example | 13 +++++-------- lightrag/api/README-zh.md | 22 +++++++--------------- lightrag/api/README.md | 22 ++++++++-------------- lightrag/api/gunicorn_config.py | 3 +++ lightrag/api/lightrag_server.py | 13 ++++++++----- lightrag/api/run_with_gunicorn.py | 4 +--- lightrag/kg/shared_storage.py | 10 +++------- 8 files changed, 35 insertions(+), 56 deletions(-) delete mode 100644 lightrag-api diff --git a/lightrag-api b/lightrag-api deleted file mode 100644 index 89c814fb..00000000 --- a/lightrag-api +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/bash - -source /home/netman/lightrag-xyj/venv/bin/activate -lightrag-server diff --git a/lightrag.service.example b/lightrag.service.example index e99198d1..3a342c5b 100644 --- a/lightrag.service.example +++ b/lightrag.service.example @@ -9,14 +9,11 @@ User=netman MemoryHigh=8G MemoryMax=12G -# Set the LightRAG installation directory (change this to match your installation path) -Environment="LIGHTRAG_HOME=/home/netman/lightrag-xyj" - -# Set Environment to your Python virtual environment -Environment="PATH=${LIGHTRAG_HOME}/.venv/bin" -WorkingDirectory=${LIGHTRAG_HOME} -ExecStart=${LIGHTRAG_HOME}/.venv/bin/lightrag-server -# ExecStart=${LIGHTRAG_HOME}/.venv/bin/lightrag-gunicorn +# Using virtual enviroment created by miniconda +Environment="PATH=/home/netman/miniconda3/bin:/home/netman/lightrag-xyj/venv/bin" +WorkingDirectory=/home/netman/lightrag-xyj +# ExecStart=/home/netman/lightrag-xyj/venv/bin/lightrag-server +ExecStart=/home/netman/lightrag-xyj/venv/bin/lightrag-gunicorn # Kill mode require ExecStart must be gunicorn or unvicorn main process KillMode=process diff --git a/lightrag/api/README-zh.md b/lightrag/api/README-zh.md index 62f581fd..dec56499 100644 --- a/lightrag/api/README-zh.md +++ b/lightrag/api/README-zh.md @@ -210,24 +210,16 @@ MAX_ASYNC=4 ### 将 Lightrag 安装为 Linux 服务 -从示例文件 `lightrag.service.example` 创建您的服务文件 `lightrag.service`。修改服务文件中的 WorkingDirectory 和 ExecStart: +从示例文件 `lightrag.service.example` 创建您的服务文件 `lightrag.service`。修改服务文件中的服务启动定义: ```text -Description=LightRAG Ollama Service -WorkingDirectory= -ExecStart=/lightrag/api/lightrag-api -``` - -修改您的服务启动脚本:`lightrag-api`。根据需要更改 python 虚拟环境激活命令: - -```shell -#!/bin/bash - -# 您的 python 虚拟环境激活命令 -source /home/netman/lightrag-xyj/venv/bin/activate -# 启动 lightrag api 服务器 -lightrag-server +# Set Enviroment to your Python virtual enviroment +Environment="PATH=/home/netman/lightrag-xyj/venv/bin" +WorkingDirectory=/home/netman/lightrag-xyj +# ExecStart=/home/netman/lightrag-xyj/venv/bin/lightrag-server +ExecStart=/home/netman/lightrag-xyj/venv/bin/lightrag-gunicorn ``` +> ExecStart命令必须是 lightrag-gunicorn 或 lightrag-server 中的一个,不能使用其它脚本包裹它们。因为停止服务必须要求主进程必须是这两个进程。 安装 LightRAG 服务。如果您的系统是 Ubuntu,以下命令将生效: diff --git a/lightrag/api/README.md b/lightrag/api/README.md index 09e2f0db..02524a49 100644 --- a/lightrag/api/README.md +++ b/lightrag/api/README.md @@ -212,24 +212,18 @@ MAX_ASYNC=4 ### Install LightRAG as a Linux Service -Create your service file `lightrag.service` from the sample file: `lightrag.service.example`. Modify the `WorkingDirectory` and `ExecStart` in the service file: +Create your service file `lightrag.service` from the sample file: `lightrag.service.example`. Modify the start options the service file: ```text -Description=LightRAG Ollama Service -WorkingDirectory= -ExecStart=/lightrag/api/lightrag-api +# Set Enviroment to your Python virtual enviroment +Environment="PATH=/home/netman/lightrag-xyj/venv/bin" +WorkingDirectory=/home/netman/lightrag-xyj +# ExecStart=/home/netman/lightrag-xyj/venv/bin/lightrag-server +ExecStart=/home/netman/lightrag-xyj/venv/bin/lightrag-gunicorn + ``` -Modify your service startup script: `lightrag-api`. Change your Python virtual environment activation command as needed: - -```shell -#!/bin/bash - -# your python virtual environment activation -source /home/netman/lightrag-xyj/venv/bin/activate -# start lightrag api server -lightrag-server -``` +> The ExecStart command must be either `lightrag-gunicorn` or `lightrag-server`; no wrapper scripts are allowed. This is because service termination requires the main process to be one of these two executables. Install LightRAG service. If your system is Ubuntu, the following commands will work: diff --git a/lightrag/api/gunicorn_config.py b/lightrag/api/gunicorn_config.py index 65a68d90..c730cbf7 100644 --- a/lightrag/api/gunicorn_config.py +++ b/lightrag/api/gunicorn_config.py @@ -133,6 +133,9 @@ def on_exit(server): print("Finalizing shared storage...") finalize_share_data() + print("Gunicorn shutdown complete") + print("=" * 80) + print("=" * 80) print("=" * 80) diff --git a/lightrag/api/lightrag_server.py b/lightrag/api/lightrag_server.py index 47513b77..3269fbb5 100644 --- a/lightrag/api/lightrag_server.py +++ b/lightrag/api/lightrag_server.py @@ -326,12 +326,15 @@ def create_app(args): # Clean up database connections await rag.finalize_storages() - # 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 + if "LIGHTRAG_GUNICORN_MODE" not in os.environ: + # Only perform cleanup in Uvicorn single-process mode + logger.debug("Unvicorn Mode: finalizing shared storage...") finalize_share_data() + else: + # In Gunicorn mode with preload_app=True, cleanup is handled by on_exit hooks + logger.debug( + "Gunicorn Mode: postpone shared storage finalization to master process" + ) # Initialize FastAPI base_description = ( diff --git a/lightrag/api/run_with_gunicorn.py b/lightrag/api/run_with_gunicorn.py index c5f7cb5c..f2d4d859 100644 --- a/lightrag/api/run_with_gunicorn.py +++ b/lightrag/api/run_with_gunicorn.py @@ -45,9 +45,7 @@ def main(): check_and_install_dependencies() # Note: Signal handlers are NOT registered here because: - # - Worker cleanup is handled by gunicorn_config.worker_exit() - # - Master cleanup is handled by gunicorn_config.on_exit() - # This prevents race conditions when multiple processes try to finalize shared data + # - Master cleanup already handled by gunicorn_config.on_exit() # Display startup information display_splash_screen(global_args) diff --git a/lightrag/kg/shared_storage.py b/lightrag/kg/shared_storage.py index 3d47eab8..ef0f61e2 100644 --- a/lightrag/kg/shared_storage.py +++ b/lightrag/kg/shared_storage.py @@ -1565,7 +1565,7 @@ def get_namespace_lock( return NamespaceLock(namespace, workspace, enable_logging) -def finalize_share_data(shutdown_manager: bool = True): +def finalize_share_data(): """ Release shared resources and clean up. @@ -1574,10 +1574,6 @@ def finalize_share_data(shutdown_manager: bool = True): In multi-process mode, it shuts down the Manager and releases all shared objects. In single-process mode, it simply resets the global variables. - - Args: - shutdown_manager: If True, shut down the multiprocessing Manager. - Should be True only for the main process, False for worker processes. """ global \ _manager, \ @@ -1602,8 +1598,8 @@ def finalize_share_data(shutdown_manager: bool = True): f"Process {os.getpid()} finalizing storage data (multiprocess={_is_multiprocess})" ) - # In multi-process mode, shut down the Manager only if requested - if _is_multiprocess and _manager is not None and shutdown_manager: + # In multi-process mode, shut down the Manager + if _is_multiprocess and _manager is not None: try: # Clear shared resources before shutting down Manager if _shared_dicts is not None: