워커 시작 훅

워커 시작 훅 (Worker Startup Hooks)

LITELLM_WORKER_STARTUP_HOOKS를 사용해 프록시 시작 시 각 워커 프로세스에서 커스텀 초기화 함수를 실행하는 방법이에요. gflags 같은 프로세스별 초기화가 필요한 라이브러리를 쓰는 멀티 워커 배포(--num_workers > 1)에서 필수적이에요.

출처: 문서

본문

LITELLM_WORKER_STARTUP_HOOKS를 사용해 프록시 시작 시 각 워커 프로세스에서 커스텀 초기화 함수를 실행해요. gflags처럼 프로세스별 초기화가 필요한 라이브러리를 쓰는 멀티 워커 배포(--num_workers > 1)에서 필수적이에요.

문제

멀티 워커로 LiteLLM 프록시를 실행할 때:

litellm --config config.yaml --num_workers 4

각 워커는 uvicorn, gunicorn, 또는 Granian(--run_granian)이 생성한 별도 프로세스예요. 마스터 프로세스에서(run_server() 전에) 초기화된 모든 인-프로세스 상태는 워커 프로세스에서 사용할 수 없어요. 여기에는 다음이 포함돼요:

  • python-gflags (gflags.FLAGS)
  • absl-py flags (absl.flags.FLAGS)
  • 커스텀 싱글톤 레지스트리나 연결 풀
  • 명시적 초기화가 필요한 모든 모듈 수준 상태

사용법

LITELLM_WORKER_STARTUP_HOOKS 환경 변수를 module.path:function_name 콜러블의 쉼표로 구분된 목록으로 설정해요:

export LITELLM_WORKER_STARTUP_HOOKS="my_module:my_init_function"

각 훅은 config 로딩, 데이터베이스 설정, 요청 처리가 시작되기 전인 워커 시작 생애주기의 이른 시점에 호출돼요. 동기 및 비동기 함수 모두 지원돼요.

예시: gflags 초기화

1. 래퍼 모듈 정의하기

my_litellm_wrapper.py

import gflags
import json
import os
import sys
from typing import Optional, List, Any

def init_gflags(
    usage: Optional[Any] = None,
    raw_args: Optional[List[str]] = None,
    known_only: bool = False,
) -> List[str]:
    """Initialize gflags from command-line arguments."""
    try:
        gflags.FLAGS.set_gnu_getopt(True)
        if raw_args is None:
            raw_args = sys.argv
        argv = gflags.FLAGS(raw_args, known_only=known_only)
    except gflags.Error as e:
        if usage is None:
            print("%s\nUsage: %s ARGS\n%s" % (e, sys.argv[0], gflags.FLAGS))
        else:
            print(usage % dict(cmd=sys.argv[0], flags=gflags.FLAGS))
        sys.exit(1)
    return argv

def init_gflags_for_worker():
    """Re-initialize gflags in each worker process.

    Reads the original sys.argv from the GFLAGS_ARGV env var
    (set by the master process before starting the proxy).
    """
    raw_args = json.loads(os.environ.get("GFLAGS_ARGV", "[]")) or sys.argv
    init_gflags(raw_args=raw_args, known_only=True)

2. 프록시 시작하기

start_proxy.py

import json
import os
import sys

from my_litellm_wrapper import init_gflags

# Store sys.argv so workers can re-parse the same flags
os.environ["GFLAGS_ARGV"] = json.dumps(sys.argv)

# Tell LiteLLM to call our hook in each worker
os.environ["LITELLM_WORKER_STARTUP_HOOKS"] = "my_litellm_wrapper:init_gflags_for_worker"

# Initialize gflags in the master process
init_gflags()

# Start the proxy (programmatic invocation)
from litellm.proxy.proxy_cli import run_server

run_server(
    ["--config", "config.yaml", "--num_workers", "4"],
    standalone_mode=False,
)

또는 셸로:

export GFLAGS_ARGV='["my_app", "--my_flag=value", "--batch_size=32"]'
export LITELLM_WORKER_STARTUP_HOOKS="my_litellm_wrapper:init_gflags_for_worker"

litellm --config config.yaml --num_workers 4

동작 방식

Master Process                          Worker Process (×N)
─────────────────                       ──────────────────────
1. init_gflags()                        3. proxy_startup_event():
2. run_server()                            → Read LITELLM_WORKER_STARTUP_HOOKS
   → sets env vars                         → Import & call each hook
   → uvicorn.run(workers=N)                  (gflags.FLAGS re-initialized ✓)
   → spawns workers ──────────────────►    → Continue with config/DB setup
                                           → Ready to serve requests
  • 훅은 proxy_startup_event(FastAPI lifespan)의 맨 앞에서, config 로딩, DB 연결, 다른 초기화 이전에 실행돼요.
  • 마스터 프로세스에서 설정한 환경 변수는 표준 Unix fork/spawn 동작으로 워커 프로세스에 상속돼요.
  • 훅이 예외를 던지면 워커가 시작에 실패해요. 초기화 누락(예: 초기화되지 않은 gflags)이 다운스트림 오류를 일으키기 때문에 의도적인 동작이에요.

여러 훅

여러 훅은 쉼표로 구분해요:

export LITELLM_WORKER_STARTUP_HOOKS="my_module:init_gflags,my_module:init_metrics,my_module:init_connections"

훅은 왼쪽에서 오른쪽 순서로 실행돼요.

비동기 훅

비동기 함수도 지원되며 자동으로 await돼요:

async def init_async_connections():
    """Example async hook for initializing async resources."""
    await setup_async_connection_pool()
export LITELLM_WORKER_STARTUP_HOOKS="my_module:init_async_connections"

레퍼런스

환경 변수 설명
LITELLM_WORKER_STARTUP_HOOKS 시작 시 각 워커에서 실행할 쉼표로 구분된 module.path:function_name 콜러블

훅 형식은 표준 Python 진입점 문법 module.path:function_name을 따르며, 여기서 module.path는 점으로 된 Python 임포트 경로이고 function_name은 그 모듈 안의 콜러블 이름이에요.

더 알아보기 (Learn more)