2025-02-27 13:25:22 +08:00
|
|
|
# gunicorn_config.py
|
|
|
|
import os
|
2025-02-28 14:57:25 +08:00
|
|
|
import logging
|
|
|
|
from logging.config import dictConfig
|
|
|
|
from logging.handlers import RotatingFileHandler
|
2025-02-27 13:25:22 +08:00
|
|
|
from lightrag.kg.shared_storage import finalize_share_data
|
|
|
|
from lightrag.api.utils_api import parse_args
|
|
|
|
|
|
|
|
# Parse command line arguments
|
|
|
|
args = parse_args()
|
|
|
|
|
|
|
|
# Determine worker count - from environment variable or command line arguments
|
2025-02-27 19:05:51 +08:00
|
|
|
workers = int(os.getenv("WORKERS", args.workers))
|
2025-02-27 13:25:22 +08:00
|
|
|
|
|
|
|
# Binding address
|
|
|
|
bind = f"{os.getenv('HOST', args.host)}:{os.getenv('PORT', args.port)}"
|
|
|
|
|
|
|
|
# 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
|
|
|
|
|
|
|
|
# Optional SSL configuration
|
|
|
|
if args.ssl:
|
|
|
|
certfile = args.ssl_certfile
|
|
|
|
keyfile = args.ssl_keyfile
|
|
|
|
|
2025-02-28 14:57:25 +08:00
|
|
|
# 获取日志文件路径
|
|
|
|
log_file_path = os.path.abspath(os.path.join(os.getcwd(), "lightrag.log"))
|
|
|
|
|
2025-02-27 13:25:22 +08:00
|
|
|
# Logging configuration
|
2025-02-28 14:57:25 +08:00
|
|
|
errorlog = os.getenv("ERROR_LOG", log_file_path) # 默认写入到 lightrag.log
|
|
|
|
accesslog = os.getenv("ACCESS_LOG", log_file_path) # 默认写入到 lightrag.log
|
2025-02-27 19:05:51 +08:00
|
|
|
loglevel = os.getenv("LOG_LEVEL", "info")
|
|
|
|
|
2025-02-28 14:57:25 +08:00
|
|
|
# 配置日志系统
|
|
|
|
logconfig_dict = {
|
|
|
|
'version': 1,
|
|
|
|
'disable_existing_loggers': False,
|
|
|
|
'formatters': {
|
|
|
|
'standard': {
|
|
|
|
'format': '%(asctime)s [%(levelname)s] %(name)s: %(message)s'
|
|
|
|
},
|
|
|
|
},
|
|
|
|
'handlers': {
|
|
|
|
'console': {
|
|
|
|
'class': 'logging.StreamHandler',
|
|
|
|
'level': 'INFO',
|
|
|
|
'formatter': 'standard',
|
|
|
|
'stream': 'ext://sys.stdout'
|
|
|
|
},
|
|
|
|
'file': {
|
|
|
|
'class': 'logging.handlers.RotatingFileHandler',
|
|
|
|
'level': 'INFO',
|
|
|
|
'formatter': 'standard',
|
|
|
|
'filename': log_file_path,
|
|
|
|
'maxBytes': 10485760, # 10MB
|
|
|
|
'backupCount': 5,
|
|
|
|
'encoding': 'utf8'
|
|
|
|
}
|
|
|
|
},
|
|
|
|
'loggers': {
|
|
|
|
'lightrag': {
|
|
|
|
'handlers': ['console', 'file'],
|
|
|
|
'level': 'INFO',
|
|
|
|
'propagate': False
|
|
|
|
},
|
2025-02-28 16:07:33 +08:00
|
|
|
'gunicorn': {
|
2025-02-28 14:57:25 +08:00
|
|
|
'handlers': ['console', 'file'],
|
|
|
|
'level': 'INFO',
|
|
|
|
'propagate': False
|
|
|
|
},
|
2025-02-28 16:07:33 +08:00
|
|
|
'gunicorn.error': {
|
2025-02-28 14:57:25 +08:00
|
|
|
'handlers': ['console', 'file'],
|
|
|
|
'level': 'INFO',
|
|
|
|
'propagate': False
|
|
|
|
},
|
2025-02-28 16:07:33 +08:00
|
|
|
'gunicorn.access': {
|
2025-02-28 14:57:25 +08:00
|
|
|
'handlers': ['console', 'file'],
|
|
|
|
'level': 'INFO',
|
|
|
|
'propagate': False
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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)
|