cherry-pick 72b29659
This commit is contained in:
parent
1db4d81dbb
commit
8ebd98ae8e
3 changed files with 33 additions and 22 deletions
|
|
@ -163,3 +163,24 @@ 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.
|
||||
|
||||
This is called for each worker process when it exits. We should only
|
||||
clean up worker-local resources here, 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)
|
||||
|
|
|
|||
|
|
@ -5,12 +5,11 @@ Start LightRAG server with Gunicorn
|
|||
|
||||
import os
|
||||
import sys
|
||||
import signal
|
||||
import pipmaster as pm
|
||||
from lightrag.api.utils_api import display_splash_screen, check_env_file
|
||||
from lightrag.api.config import global_args
|
||||
from lightrag.utils import get_env_value
|
||||
from lightrag.kg.shared_storage import initialize_share_data, finalize_share_data
|
||||
from lightrag.kg.shared_storage import initialize_share_data
|
||||
|
||||
from lightrag.constants import (
|
||||
DEFAULT_WOKERS,
|
||||
|
|
@ -34,20 +33,6 @@ def check_and_install_dependencies():
|
|||
print(f"{package} installed successfully")
|
||||
|
||||
|
||||
# Signal handler for graceful shutdown
|
||||
def signal_handler(sig, frame):
|
||||
print("\n\n" + "=" * 80)
|
||||
print("RECEIVED TERMINATION SIGNAL")
|
||||
print(f"Process ID: {os.getpid()}")
|
||||
print("=" * 80 + "\n")
|
||||
|
||||
# Release shared resources
|
||||
finalize_share_data()
|
||||
|
||||
# Exit with success status
|
||||
sys.exit(0)
|
||||
|
||||
|
||||
def main():
|
||||
# Set Gunicorn mode flag for lifespan cleanup detection
|
||||
os.environ["LIGHTRAG_GUNICORN_MODE"] = "1"
|
||||
|
|
@ -59,9 +44,10 @@ def main():
|
|||
# Check and install dependencies
|
||||
check_and_install_dependencies()
|
||||
|
||||
# Register signal handlers for graceful shutdown
|
||||
signal.signal(signal.SIGINT, signal_handler) # Ctrl+C
|
||||
signal.signal(signal.SIGTERM, signal_handler) # kill command
|
||||
# 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
|
||||
|
||||
# Display startup information
|
||||
display_splash_screen(global_args)
|
||||
|
|
|
|||
|
|
@ -1565,7 +1565,7 @@ def get_namespace_lock(
|
|||
return NamespaceLock(namespace, workspace, enable_logging)
|
||||
|
||||
|
||||
def finalize_share_data():
|
||||
def finalize_share_data(shutdown_manager: bool = True):
|
||||
"""
|
||||
Release shared resources and clean up.
|
||||
|
||||
|
|
@ -1574,6 +1574,10 @@ def finalize_share_data():
|
|||
|
||||
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, \
|
||||
|
|
@ -1598,8 +1602,8 @@ def finalize_share_data():
|
|||
f"Process {os.getpid()} finalizing storage data (multiprocess={_is_multiprocess})"
|
||||
)
|
||||
|
||||
# In multi-process mode, shut down the Manager
|
||||
if _is_multiprocess and _manager is not None:
|
||||
# In multi-process mode, shut down the Manager only if requested
|
||||
if _is_multiprocess and _manager is not None and shutdown_manager:
|
||||
try:
|
||||
# Clear shared resources before shutting down Manager
|
||||
if _shared_dicts is not None:
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue