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 3c96e0b4..3a342c5b 100644 --- a/lightrag.service.example +++ b/lightrag.service.example @@ -1,5 +1,5 @@ [Unit] -Description=LightRAG XYJ Ollama Service +Description=LightRAG XYJ Service After=network.target [Service] @@ -8,10 +8,20 @@ User=netman # Memory settings MemoryHigh=8G MemoryMax=12G + +# 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/lightrag-api +# 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 +ExecStop=/bin/kill -s TERM $MAINPID +TimeoutStopSec=60 + Restart=always -RestartSec=10 +RestartSec=30 [Install] WantedBy=multi-user.target diff --git a/lightrag/api/README-zh.md b/lightrag/api/README-zh.md index 692c589d..bd2bbd62 100644 --- a/lightrag/api/README-zh.md +++ b/lightrag/api/README-zh.md @@ -184,24 +184,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 aa24576e..8bf9e281 100644 --- a/lightrag/api/README.md +++ b/lightrag/api/README.md @@ -188,24 +188,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 7b25b5b9..e000b46c 100644 --- a/lightrag/api/gunicorn_config.py +++ b/lightrag/api/gunicorn_config.py @@ -129,11 +129,13 @@ def on_exit(server): print("=" * 80) print("GUNICORN MASTER PROCESS: Shutting down") print(f"Process ID: {os.getpid()}") - print("=" * 80) - # Release shared resources + print("Finalizing shared storage...") finalize_share_data() + print("Gunicorn shutdown complete") + print("=" * 80) + print("=" * 80) print("Gunicorn shutdown complete") print("=" * 80) diff --git a/lightrag/api/lightrag_server.py b/lightrag/api/lightrag_server.py index ec8b2f45..3269fbb5 100644 --- a/lightrag/api/lightrag_server.py +++ b/lightrag/api/lightrag_server.py @@ -326,15 +326,14 @@ 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 "LIGHTRAG_GUNICORN_MODE" not in os.environ: - # Clean up shared data - logger.debug("Unvicorn Mode: finalize shared storage...") + # 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: don not finalize shared storage in worker process" + "Gunicorn Mode: postpone shared storage finalization to master process" ) # Initialize FastAPI 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 c7dc03e5..0abcf719 100644 --- a/lightrag/kg/shared_storage.py +++ b/lightrag/kg/shared_storage.py @@ -1444,7 +1444,7 @@ async def get_namespace_data( return _shared_dicts[namespace] -def finalize_share_data(shutdown_manager: bool = True): +def finalize_share_data(): """ Release shared resources and clean up. @@ -1453,10 +1453,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, \ @@ -1483,8 +1479,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: