|
|
|
""" |
|
Start LightRAG server with Gunicorn |
|
""" |
|
|
|
import os |
|
import sys |
|
import signal |
|
import pipmaster as pm |
|
from lightrag.api.utils_api import parse_args, display_splash_screen |
|
from lightrag.kg.shared_storage import initialize_share_data, finalize_share_data |
|
|
|
|
|
def check_and_install_dependencies(): |
|
"""Check and install required dependencies""" |
|
required_packages = [ |
|
"gunicorn", |
|
"tiktoken", |
|
|
|
] |
|
|
|
for package in required_packages: |
|
if not pm.is_installed(package): |
|
print(f"Installing {package}...") |
|
pm.install(package) |
|
print(f"{package} installed successfully") |
|
|
|
|
|
|
|
def signal_handler(sig, frame): |
|
print("\n\n" + "=" * 80) |
|
print("RECEIVED TERMINATION SIGNAL") |
|
print(f"Process ID: {os.getpid()}") |
|
print("=" * 80 + "\n") |
|
|
|
|
|
finalize_share_data() |
|
|
|
|
|
sys.exit(0) |
|
|
|
|
|
def main(): |
|
|
|
check_and_install_dependencies() |
|
|
|
|
|
signal.signal(signal.SIGINT, signal_handler) |
|
signal.signal(signal.SIGTERM, signal_handler) |
|
|
|
|
|
args = parse_args(is_uvicorn_mode=False) |
|
|
|
|
|
display_splash_screen(args) |
|
|
|
print("🚀 Starting LightRAG with Gunicorn") |
|
print(f"🔄 Worker management: Gunicorn (workers={args.workers})") |
|
print("🔍 Preloading app: Enabled") |
|
print("📝 Note: Using Gunicorn's preload feature for shared data initialization") |
|
print("\n\n" + "=" * 80) |
|
print("MAIN PROCESS INITIALIZATION") |
|
print(f"Process ID: {os.getpid()}") |
|
print(f"Workers setting: {args.workers}") |
|
print("=" * 80 + "\n") |
|
|
|
|
|
from gunicorn.app.base import BaseApplication |
|
|
|
|
|
class GunicornApp(BaseApplication): |
|
def __init__(self, app, options=None): |
|
self.options = options or {} |
|
self.application = app |
|
super().__init__() |
|
|
|
def load_config(self): |
|
|
|
valid_options = { |
|
"bind", |
|
"workers", |
|
"worker_class", |
|
"timeout", |
|
"keepalive", |
|
"preload_app", |
|
"errorlog", |
|
"accesslog", |
|
"loglevel", |
|
"certfile", |
|
"keyfile", |
|
"limit_request_line", |
|
"limit_request_fields", |
|
"limit_request_field_size", |
|
"graceful_timeout", |
|
"max_requests", |
|
"max_requests_jitter", |
|
} |
|
|
|
|
|
special_hooks = { |
|
"on_starting", |
|
"on_reload", |
|
"on_exit", |
|
"pre_fork", |
|
"post_fork", |
|
"pre_exec", |
|
"pre_request", |
|
"post_request", |
|
"worker_init", |
|
"worker_exit", |
|
"nworkers_changed", |
|
"child_exit", |
|
} |
|
|
|
|
|
import gunicorn_config |
|
|
|
|
|
gunicorn_config.workers = ( |
|
args.workers if args.workers else int(os.getenv("WORKERS", 1)) |
|
) |
|
|
|
|
|
host = args.host if args.host != "0.0.0.0" else os.getenv("HOST", "0.0.0.0") |
|
port = args.port if args.port != 9621 else int(os.getenv("PORT", 9621)) |
|
gunicorn_config.bind = f"{host}:{port}" |
|
|
|
|
|
gunicorn_config.loglevel = ( |
|
args.log_level.lower() |
|
if args.log_level |
|
else os.getenv("LOG_LEVEL", "info") |
|
) |
|
|
|
|
|
gunicorn_config.timeout = ( |
|
args.timeout if args.timeout else int(os.getenv("TIMEOUT", 150)) |
|
) |
|
|
|
|
|
gunicorn_config.keepalive = int(os.getenv("KEEPALIVE", 5)) |
|
|
|
|
|
if args.ssl or os.getenv("SSL", "").lower() in ( |
|
"true", |
|
"1", |
|
"yes", |
|
"t", |
|
"on", |
|
): |
|
gunicorn_config.certfile = ( |
|
args.ssl_certfile |
|
if args.ssl_certfile |
|
else os.getenv("SSL_CERTFILE") |
|
) |
|
gunicorn_config.keyfile = ( |
|
args.ssl_keyfile if args.ssl_keyfile else os.getenv("SSL_KEYFILE") |
|
) |
|
|
|
|
|
for key in dir(gunicorn_config): |
|
if key in valid_options: |
|
value = getattr(gunicorn_config, key) |
|
|
|
if not callable(value) and value is not None: |
|
self.cfg.set(key, value) |
|
|
|
elif key in special_hooks: |
|
value = getattr(gunicorn_config, key) |
|
if callable(value): |
|
self.cfg.set(key, value) |
|
|
|
if hasattr(gunicorn_config, "logconfig_dict"): |
|
self.cfg.set( |
|
"logconfig_dict", getattr(gunicorn_config, "logconfig_dict") |
|
) |
|
|
|
def load(self): |
|
|
|
from lightrag.api.lightrag_server import get_application |
|
|
|
return get_application(args) |
|
|
|
|
|
app = GunicornApp("") |
|
|
|
|
|
workers_count = int(args.workers) |
|
if workers_count > 1: |
|
|
|
os.environ["LIGHTRAG_MAIN_PROCESS"] = "1" |
|
initialize_share_data(workers_count) |
|
else: |
|
initialize_share_data(1) |
|
|
|
|
|
print("\nStarting Gunicorn with direct Python API...") |
|
app.run() |
|
|
|
|
|
if __name__ == "__main__": |
|
main() |
|
|