| 1 | # SPDX-License-Identifier: Apache-2.0 |
| 2 | # SPDX-FileCopyrightText: Copyright contributors to the vLLM project |
| 3 | import argparse |
| 4 | import asyncio |
| 5 | import signal |
| 6 | import socket |
| 7 | from argparse import Namespace |
| 8 | |
| 9 | from vllm import AsyncEngineArgs, envs |
| 10 | from vllm.config import VllmConfig |
| 11 | from vllm.logger import configure_logging_from_args, init_logger |
| 12 | |
| 13 | from ..app import build_app |
| 14 | from ..launcher import serve_http, setup_server |
| 15 | from ..utils.server_utils import get_uvicorn_log_config |
| 16 | from .app_state import init_render_app_state |
| 17 | |
| 18 | logger = init_logger("vllm.entrypoints.launchers.render.entry") |
| 19 | |
| 20 | |
| 21 | async def build_and_serve_renderer( |
| 22 | vllm_config: VllmConfig, |
| 23 | listen_address: str, |
| 24 | sock: socket.socket, |
| 25 | args: Namespace, |
| 26 | **uvicorn_kwargs, |
| 27 | ) -> asyncio.Task: |
| 28 | """Build FastAPI app for a CPU-only render server, initialize state, and |
| 29 | start serving. |
| 30 | |
| 31 | Returns the shutdown task for the caller to await. |
| 32 | """ |
| 33 | # Get uvicorn log config (from file or with endpoint filter) |
| 34 | log_config = get_uvicorn_log_config(args) |
| 35 | if log_config is not None: |
| 36 | uvicorn_kwargs["log_config"] = log_config |
| 37 | |
| 38 | app = build_app(args, ("render",)) |
| 39 | await init_render_app_state(vllm_config, app.state, args) |
| 40 | |
| 41 | logger.info("Starting vLLM server on %s", listen_address) |
| 42 | |
| 43 | return await serve_http( |
| 44 | app, |
| 45 | sock=sock, |
| 46 | enable_ssl_refresh=args.enable_ssl_refresh, |
| 47 | host=args.host, |
| 48 | port=args.port, |
| 49 | log_level=args.uvicorn_log_level, |
| 50 | # NOTE: When the 'disable_uvicorn_access_log' value is True, |
| 51 | # no access log will be output. |
| 52 | access_log=not args.disable_uvicorn_access_log, |
| 53 | timeout_keep_alive=envs.VLLM_HTTP_TIMEOUT_KEEP_ALIVE, |
| 54 | ssl_keyfile=args.ssl_keyfile, |
| 55 | ssl_certfile=args.ssl_certfile, |
| 56 | ssl_ca_certs=args.ssl_ca_certs, |
| 57 | ssl_cert_reqs=args.ssl_cert_reqs, |
| 58 | ssl_ciphers=args.ssl_ciphers, |
| 59 | h11_max_incomplete_event_size=args.h11_max_incomplete_event_size, |
| 60 | h11_max_header_count=args.h11_max_header_count, |
| 61 | **uvicorn_kwargs, |
| 62 | ) |
| 63 | |
| 64 | |
| 65 | async def run_launch_fastapi(args: argparse.Namespace) -> None: |
| 66 | """Run the online serving layer with FastAPI (no GPU inference).""" |
| 67 | |
| 68 | # Interrupt initialization if SIGTERM arrives before uvicorn installs |
| 69 | # its own signal handlers. Once uvicorn is running it replaces this. |
| 70 | def _interrupt_init(*_) -> None: |
| 71 | raise KeyboardInterrupt("terminated") |
| 72 | |
| 73 | signal.signal(signal.SIGTERM, _interrupt_init) |
| 74 | |
| 75 | # 1. Socket binding |
| 76 | listen_address, sock = setup_server(args, reuse_port=False) |
| 77 | |
| 78 | # 2. Build and serve the API server |
| 79 | engine_args = AsyncEngineArgs.from_cli_args(args) |
| 80 | model_config = engine_args.create_model_config() |
| 81 | |
| 82 | # Render servers preprocess data only — no inference, no quantized kernels. |
| 83 | # Clear quantization so VllmConfig skips quant dtype/capability validation. |
| 84 | model_config.quantization = None |
| 85 | |
| 86 | # Render servers never allocate KV cache; suppress the spurious CPU KV |
| 87 | # cache space warning from CpuPlatform.check_and_update_config. |
| 88 | envs.VLLM_CPU_KVCACHE_SPACE = 0 |
| 89 | |
| 90 | vllm_config = VllmConfig( |
| 91 | model_config=model_config, |
| 92 | logging_config=engine_args.create_logging_config(), |
| 93 | ) |
| 94 | shutdown_task = await build_and_serve_renderer( |
| 95 | vllm_config, listen_address, sock, args |
| 96 | ) |
| 97 | try: |
| 98 | await shutdown_task |
| 99 | finally: |
| 100 | sock.close() |
| 101 | |
| 102 | |
| 103 | if __name__ == "__main__": |
| 104 | import uvloop |
| 105 | |
| 106 | from vllm.entrypoints.serve.utils.api_utils import cli_env_setup |
| 107 | from vllm.utils.argparse_utils import FlexibleArgumentParser |
| 108 | |
| 109 | from ..cli_args import ( |
| 110 | make_arg_parser, |
| 111 | validate_parsed_serve_args, |
| 112 | ) |
| 113 | |
| 114 | cli_env_setup() |
| 115 | parser = FlexibleArgumentParser( |
| 116 | description="Starts a GPU-less rendering server " |
| 117 | "for preprocessing and postprocessing only" |
| 118 | ) |
| 119 | parser = make_arg_parser(parser) |
| 120 | args = parser.parse_args() |
| 121 | configure_logging_from_args(args) |
| 122 | validate_parsed_serve_args(args) |
| 123 | |
| 124 | uvloop.run(run_launch_fastapi(args)) |