|
|
|
""" |
|
Start LightRAG server with Gunicorn |
|
""" |
|
|
|
import os |
|
import sys |
|
import signal |
|
from lightrag.api.utils_api import parse_args, display_splash_screen |
|
from lightrag.kg.shared_storage import initialize_share_data, finalize_share_data |
|
|
|
|
|
|
|
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(): |
|
|
|
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 = int(os.getenv("WORKERS", args.workers)) |
|
gunicorn_config.bind = ( |
|
f"{os.getenv('HOST', args.host)}:{os.getenv('PORT', args.port)}" |
|
) |
|
gunicorn_config.loglevel = ( |
|
args.log_level.lower() |
|
if args.log_level |
|
else os.getenv("LOG_LEVEL", "info") |
|
) |
|
|
|
|
|
if args.ssl: |
|
gunicorn_config.certfile = args.ssl_certfile |
|
gunicorn_config.keyfile = args.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() |
|
|