2025-02-27 13:25:22 +08:00
|
|
|
# gunicorn_config.py
|
|
|
|
import os
|
2025-02-28 14:57:25 +08:00
|
|
|
import logging
|
2025-02-27 13:25:22 +08:00
|
|
|
from lightrag.kg.shared_storage import finalize_share_data
|
2025-02-28 17:45:40 +08:00
|
|
|
from lightrag.api.lightrag_server import LightragPathFilter
|
2025-02-27 13:25:22 +08:00
|
|
|
|
2025-02-28 23:21:14 +08:00
|
|
|
# Get log directory path from environment variable
|
|
|
|
log_dir = os.getenv("LOG_DIR", os.getcwd())
|
|
|
|
log_file_path = os.path.abspath(os.path.join(log_dir, "lightrag.log"))
|
|
|
|
|
|
|
|
# Get log file max size and backup count from environment variables
|
|
|
|
log_max_bytes = int(os.getenv("LOG_MAX_BYTES", 10485760)) # Default 10MB
|
|
|
|
log_backup_count = int(os.getenv("LOG_BACKUP_COUNT", 5)) # Default 5 backups
|
2025-02-27 13:25:22 +08:00
|
|
|
|
2025-02-28 20:41:11 +08:00
|
|
|
# These variables will be set by run_with_gunicorn.py
|
|
|
|
workers = None
|
|
|
|
bind = None
|
|
|
|
loglevel = None
|
|
|
|
certfile = None
|
|
|
|
keyfile = None
|
2025-02-27 13:25:22 +08:00
|
|
|
|
|
|
|
# Enable preload_app option
|
|
|
|
preload_app = True
|
|
|
|
|
|
|
|
# Use Uvicorn worker
|
|
|
|
worker_class = "uvicorn.workers.UvicornWorker"
|
|
|
|
|
|
|
|
# Other Gunicorn configurations
|
2025-02-27 19:05:51 +08:00
|
|
|
timeout = int(os.getenv("TIMEOUT", 120))
|
2025-02-27 13:25:22 +08:00
|
|
|
keepalive = 5
|
|
|
|
|
|
|
|
# Logging configuration
|
2025-02-28 23:21:14 +08:00
|
|
|
errorlog = os.getenv("ERROR_LOG", log_file_path) # Default write to lightrag.log
|
|
|
|
accesslog = os.getenv("ACCESS_LOG", log_file_path) # Default write to lightrag.log
|
2025-02-27 19:05:51 +08:00
|
|
|
|
2025-02-28 14:57:25 +08:00
|
|
|
logconfig_dict = {
|
2025-02-28 21:35:04 +08:00
|
|
|
"version": 1,
|
|
|
|
"disable_existing_loggers": False,
|
|
|
|
"formatters": {
|
|
|
|
"standard": {"format": "%(asctime)s [%(levelname)s] %(name)s: %(message)s"},
|
2025-02-28 14:57:25 +08:00
|
|
|
},
|
2025-02-28 21:35:04 +08:00
|
|
|
"handlers": {
|
|
|
|
"console": {
|
|
|
|
"class": "logging.StreamHandler",
|
|
|
|
"formatter": "standard",
|
|
|
|
"stream": "ext://sys.stdout",
|
|
|
|
},
|
|
|
|
"file": {
|
|
|
|
"class": "logging.handlers.RotatingFileHandler",
|
|
|
|
"formatter": "standard",
|
|
|
|
"filename": log_file_path,
|
2025-02-28 23:21:14 +08:00
|
|
|
"maxBytes": log_max_bytes,
|
|
|
|
"backupCount": log_backup_count,
|
2025-02-28 21:35:04 +08:00
|
|
|
"encoding": "utf8",
|
2025-02-28 14:57:25 +08:00
|
|
|
},
|
|
|
|
},
|
2025-02-28 21:35:04 +08:00
|
|
|
"filters": {
|
|
|
|
"path_filter": {
|
|
|
|
"()": "lightrag.api.lightrag_server.LightragPathFilter",
|
2025-02-28 17:45:40 +08:00
|
|
|
},
|
|
|
|
},
|
2025-02-28 21:35:04 +08:00
|
|
|
"loggers": {
|
|
|
|
"lightrag": {
|
|
|
|
"handlers": ["console", "file"],
|
|
|
|
"level": loglevel.upper() if loglevel else "INFO",
|
|
|
|
"propagate": False,
|
2025-02-28 14:57:25 +08:00
|
|
|
},
|
2025-02-28 21:35:04 +08:00
|
|
|
"gunicorn": {
|
|
|
|
"handlers": ["console", "file"],
|
|
|
|
"level": loglevel.upper() if loglevel else "INFO",
|
|
|
|
"propagate": False,
|
2025-02-28 14:57:25 +08:00
|
|
|
},
|
2025-02-28 21:35:04 +08:00
|
|
|
"gunicorn.error": {
|
|
|
|
"handlers": ["console", "file"],
|
|
|
|
"level": loglevel.upper() if loglevel else "INFO",
|
|
|
|
"propagate": False,
|
2025-02-28 14:57:25 +08:00
|
|
|
},
|
2025-02-28 21:35:04 +08:00
|
|
|
"gunicorn.access": {
|
|
|
|
"handlers": ["console", "file"],
|
|
|
|
"level": loglevel.upper() if loglevel else "INFO",
|
|
|
|
"propagate": False,
|
|
|
|
"filters": ["path_filter"],
|
|
|
|
},
|
|
|
|
},
|
2025-02-28 14:57:25 +08:00
|
|
|
}
|
|
|
|
|
2025-02-27 13:25:22 +08:00
|
|
|
|
|
|
|
def on_starting(server):
|
|
|
|
"""
|
|
|
|
Executed when Gunicorn starts, before forking the first worker processes
|
|
|
|
You can use this function to do more initialization tasks for all processes
|
|
|
|
"""
|
|
|
|
print("=" * 80)
|
2025-02-28 10:54:43 +08:00
|
|
|
print(f"GUNICORN MASTER PROCESS: on_starting jobs for {workers} worker(s)")
|
2025-02-27 13:25:22 +08:00
|
|
|
print(f"Process ID: {os.getpid()}")
|
|
|
|
print("=" * 80)
|
2025-02-27 19:05:51 +08:00
|
|
|
|
2025-02-27 13:25:22 +08:00
|
|
|
# Memory usage monitoring
|
|
|
|
try:
|
|
|
|
import psutil
|
2025-02-27 19:05:51 +08:00
|
|
|
|
2025-02-27 13:25:22 +08:00
|
|
|
process = psutil.Process(os.getpid())
|
|
|
|
memory_info = process.memory_info()
|
2025-02-27 19:05:51 +08:00
|
|
|
msg = (
|
|
|
|
f"Memory usage after initialization: {memory_info.rss / 1024 / 1024:.2f} MB"
|
|
|
|
)
|
2025-02-27 13:25:22 +08:00
|
|
|
print(msg)
|
|
|
|
except ImportError:
|
|
|
|
print("psutil not installed, skipping memory usage reporting")
|
2025-02-27 19:05:51 +08:00
|
|
|
|
2025-02-27 20:26:12 +08:00
|
|
|
print("Gunicorn initialization complete, forking workers...\n")
|
2025-02-27 13:25:22 +08:00
|
|
|
|
2025-02-27 19:05:51 +08:00
|
|
|
|
2025-02-27 13:25:22 +08:00
|
|
|
def on_exit(server):
|
|
|
|
"""
|
|
|
|
Executed when Gunicorn is shutting down.
|
|
|
|
This is a good place to release shared resources.
|
|
|
|
"""
|
|
|
|
print("=" * 80)
|
|
|
|
print("GUNICORN MASTER PROCESS: Shutting down")
|
|
|
|
print(f"Process ID: {os.getpid()}")
|
|
|
|
print("=" * 80)
|
2025-02-27 19:05:51 +08:00
|
|
|
|
2025-02-27 13:25:22 +08:00
|
|
|
# Release shared resources
|
|
|
|
finalize_share_data()
|
2025-02-27 19:05:51 +08:00
|
|
|
|
2025-02-27 13:25:22 +08:00
|
|
|
print("=" * 80)
|
|
|
|
print("Gunicorn shutdown complete")
|
|
|
|
print("=" * 80)
|
2025-02-28 17:45:40 +08:00
|
|
|
|
|
|
|
|
|
|
|
def post_fork(server, worker):
|
|
|
|
"""
|
|
|
|
Executed after a worker has been forked.
|
|
|
|
This is a good place to set up worker-specific configurations.
|
|
|
|
"""
|
2025-02-28 20:41:11 +08:00
|
|
|
# Set lightrag logger level in worker processes using gunicorn's loglevel
|
|
|
|
from lightrag.utils import logger
|
2025-02-28 21:35:04 +08:00
|
|
|
|
2025-02-28 20:41:11 +08:00
|
|
|
logger.setLevel(loglevel.upper())
|
2025-02-28 21:35:04 +08:00
|
|
|
|
2025-02-28 17:45:40 +08:00
|
|
|
# Disable uvicorn.error logger in worker processes
|
|
|
|
uvicorn_error_logger = logging.getLogger("uvicorn.error")
|
|
|
|
uvicorn_error_logger.setLevel(logging.CRITICAL)
|
|
|
|
uvicorn_error_logger.handlers = []
|
|
|
|
uvicorn_error_logger.propagate = False
|
2025-02-28 21:35:04 +08:00
|
|
|
|
2025-02-28 17:45:40 +08:00
|
|
|
# Add log filter to uvicorn.access handler in worker processes
|
|
|
|
uvicorn_access_logger = logging.getLogger("uvicorn.access")
|
|
|
|
path_filter = LightragPathFilter()
|
|
|
|
uvicorn_access_logger.addFilter(path_filter)
|