[Frontend] Move grpc_server to launchers. (#56746)

Signed-off-by: wang.yuqi <yuqi.wang@daocloud.io>

wang.yuqi committed Sep 14, 2026 at 13:03 UTC 67111973eeb104e83bc6707a2d0f139737b711a0
4 files changed +218 -191
tests/entrypoints/launchers/test_grpc_health.py renamed
vllm/entrypoints/cli/serve.py
+1 -1
@@ -54,7 +54,7 @@ class ServeSubcommand(CLISubcommand):
54 args.model = args.model_tag
55
56 if getattr(args, "grpc", False):
57 - from vllm.entrypoints.grpc_server import serve_grpc
57 + from vllm.entrypoints.launchers.grpc_server import serve_grpc
58
59 uvloop.run(serve_grpc(args))
60 return
vllm/entrypoints/grpc_server.py
+17 -190
@@ -1,200 +1,27 @@
1 -#!/usr/bin/env python3
1 # SPDX-License-Identifier: Apache-2.0
2 # SPDX-FileCopyrightText: Copyright contributors to the vLLM project
4 -# mypy: ignore-errors
5 -"""
6 -vLLM gRPC Server
3 +import warnings
4
8 -Starts a gRPC server backed by AsyncLLM, using the VllmEngineServicer
9 -from the smg-grpc-servicer package.
5 +from vllm.entrypoints.launchers.grpc_server import main, serve_grpc
6
11 -Usage:
12 - python -m vllm.entrypoints.grpc_server --model <model_path>
7 +warnings.warn(
8 + "`vllm.entrypoints.grpc_server is deprecated and will likely be "
9 + "unsupported in a future version. Use the corresponding function from "
10 + "`vllm.entrypoints.launchers.grpc_server` instead.",
11 + DeprecationWarning,
12 + stacklevel=1,
13 +)
14
14 -Example:
15 - python -m vllm.entrypoints.grpc_server \
16 - --model meta-llama/Llama-2-7b-hf \
17 - --host 0.0.0.0 \
18 - --port 50051
19 -"""
15 +__all__ = ["main", "serve_grpc"]
16
21 -import argparse
22 -import asyncio
23 -import signal
24 -import sys
25 -import time
17
27 -try:
28 - import grpc
29 - from grpc_health.v1 import health_pb2_grpc
30 - from grpc_reflection.v1alpha import reflection
31 - from smg_grpc_proto import vllm_engine_pb2, vllm_engine_pb2_grpc
32 - from smg_grpc_servicer.vllm.health_servicer import VllmHealthServicer
33 - from smg_grpc_servicer.vllm.servicer import VllmEngineServicer
34 -except ImportError as e:
35 - raise ImportError(
36 - "gRPC mode requires smg-grpc-servicer. "
37 - "If not installed, run: pip install vllm[grpc]. "
38 - "If already installed, there may be a broken import due to a "
39 - "version mismatch — see the chained exception above for details."
40 - ) from e
41 -
42 -import uvloop
43 -
44 -from vllm import envs
45 -from vllm.engine.arg_utils import AsyncEngineArgs
46 -from vllm.entrypoints.serve.utils.api_utils import log_version_and_model
47 -from vllm.logger import init_logger
48 -from vllm.usage.usage_lib import UsageContext
49 -from vllm.utils.argparse_utils import FlexibleArgumentParser
50 -from vllm.v1.engine.async_llm import AsyncLLM
51 -from vllm.version import __version__ as VLLM_VERSION
52 -
53 -logger = init_logger(__name__)
54 -
55 -
56 -async def serve_grpc(args: argparse.Namespace):
57 - """
58 - Main gRPC serving function.
59 -
60 - Args:
61 - args: Parsed command line arguments
62 - """
63 - log_version_and_model(logger, VLLM_VERSION, args.model)
64 - logger.info("vLLM gRPC server args: %s", args)
65 -
66 - start_time = time.time()
67 -
68 - # Create engine args
69 - engine_args = AsyncEngineArgs.from_cli_args(args)
70 -
71 - # Build vLLM config
72 - vllm_config = engine_args.create_engine_config(
73 - usage_context=UsageContext.OPENAI_API_SERVER,
74 - )
75 -
76 - # Create AsyncLLM
77 - async_llm = AsyncLLM.from_vllm_config(
78 - vllm_config=vllm_config,
79 - usage_context=UsageContext.OPENAI_API_SERVER,
80 - enable_log_requests=args.enable_log_requests,
81 - disable_log_stats=args.disable_log_stats,
82 - )
83 -
84 - # Create servicer
85 - servicer = VllmEngineServicer(async_llm, start_time)
86 -
87 - # Create gRPC server
88 - server = grpc.aio.server(
89 - options=[
90 - ("grpc.max_send_message_length", -1),
91 - ("grpc.max_receive_message_length", -1),
92 - # Tolerate client keepalive pings every 10s (default 300s is too
93 - # strict for non-streaming requests where no DATA frames flow
94 - # during generation)
95 - ("grpc.http2.min_recv_ping_interval_without_data_ms", 10000),
96 - ("grpc.keepalive_permit_without_calls", True),
97 - ],
98 - )
99 -
100 - # Add servicer to server
101 - vllm_engine_pb2_grpc.add_VllmEngineServicer_to_server(servicer, server)
102 -
103 - # Add standard gRPC health service for Kubernetes probes
104 - health_servicer = VllmHealthServicer(async_llm)
105 - health_pb2_grpc.add_HealthServicer_to_server(health_servicer, server)
106 -
107 - # Enable reflection for grpcurl and other tools
108 - service_names = (
109 - vllm_engine_pb2.DESCRIPTOR.services_by_name["VllmEngine"].full_name,
110 - "grpc.health.v1.Health",
111 - reflection.SERVICE_NAME,
112 - )
113 - reflection.enable_server_reflection(service_names, server)
114 -
115 - # Bind to address
116 - host = args.host or "0.0.0.0"
117 - address = f"{host}:{args.port}"
118 - server.add_insecure_port(address)
119 -
120 - try:
121 - # Start server
122 - await server.start()
123 - logger.info("vLLM gRPC server started on %s", address)
124 - logger.info("Server is ready to accept requests")
125 -
126 - # Start periodic stats logging (mirrors the HTTP server's lifespan task)
127 - if not args.disable_log_stats:
128 -
129 - async def _force_log():
130 - while True:
131 - await asyncio.sleep(envs.VLLM_LOG_STATS_INTERVAL)
132 - await async_llm.do_log_stats()
133 -
134 - stats_task = asyncio.create_task(_force_log())
135 - else:
136 - stats_task = None
137 -
138 - # Handle shutdown signals
139 - loop = asyncio.get_running_loop()
140 - stop_event = asyncio.Event()
141 -
142 - def signal_handler():
143 - logger.info("Received shutdown signal")
144 - stop_event.set()
145 -
146 - for sig in (signal.SIGTERM, signal.SIGINT):
147 - loop.add_signal_handler(sig, signal_handler)
148 -
149 - try:
150 - await stop_event.wait()
151 - except KeyboardInterrupt:
152 - logger.info("Interrupted by user")
153 - finally:
154 - logger.info("Shutting down vLLM gRPC server...")
155 - if stats_task is not None:
156 - stats_task.cancel()
157 - try:
158 - health_servicer.set_not_serving()
159 - except Exception: # broad: must not prevent server.stop() / shutdown()
160 - logger.warning("Failed to set health status to NOT_SERVING", exc_info=True)
161 - await server.stop(grace=5.0)
162 - logger.info("gRPC server stopped")
163 - async_llm.shutdown()
164 - logger.info("AsyncLLM engine stopped")
165 - logger.info("Shutdown complete")
166 -
167 -
168 -def main():
169 - """Main entry point for python -m vllm.entrypoints.grpc_server."""
170 - parser = FlexibleArgumentParser(
171 - description="vLLM gRPC Server",
172 - )
173 -
174 - # Server args
175 - parser.add_argument(
176 - "--host",
177 - type=str,
178 - default="0.0.0.0",
179 - help="Host to bind gRPC server to",
180 - )
181 - parser.add_argument(
182 - "--port",
183 - type=int,
184 - default=50051,
185 - help="Port to bind gRPC server to",
18 +if __name__ == "__main__":
19 + warnings.warn(
20 + "`python -m vllm.entrypoints.grpc_server is deprecated and "
21 + "will likely be unsupported in a future version. "
22 + "Please use `vllm serve <model_path> --grpc` instead.",
23 + DeprecationWarning,
24 + stacklevel=1,
25 )
187 - parser = AsyncEngineArgs.add_cli_args(parser)
26
189 - args = parser.parse_args()
190 -
191 - # Run server
192 - try:
193 - uvloop.run(serve_grpc(args))
194 - except Exception as e:
195 - logger.exception("Server failed: %s", e)
196 - sys.exit(1)
197 -
198 -
199 -if __name__ == "__main__":
27 main()
vllm/entrypoints/launchers/grpc_server.py new
+200
@@ -0,0 +1,200 @@
1 +#!/usr/bin/env python3
2 +# SPDX-License-Identifier: Apache-2.0
3 +# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
4 +# mypy: ignore-errors
5 +"""
6 +vLLM gRPC Server
7 +
8 +Starts a gRPC server backed by AsyncLLM, using the VllmEngineServicer
9 +from the smg-grpc-servicer package.
10 +
11 +Usage:
12 + python -m vllm.entrypoints.launchers.grpc_server --model <model_path>
13 +
14 +Example:
15 + python -m vllm.entrypoints.launchers.grpc_server \
16 + --model meta-llama/Llama-2-7b-hf \
17 + --host 0.0.0.0 \
18 + --port 50051
19 +"""
20 +
21 +import argparse
22 +import asyncio
23 +import signal
24 +import sys
25 +import time
26 +
27 +try:
28 + import grpc
29 + from grpc_health.v1 import health_pb2_grpc
30 + from grpc_reflection.v1alpha import reflection
31 + from smg_grpc_proto import vllm_engine_pb2, vllm_engine_pb2_grpc
32 + from smg_grpc_servicer.vllm.health_servicer import VllmHealthServicer
33 + from smg_grpc_servicer.vllm.servicer import VllmEngineServicer
34 +except ImportError as e:
35 + raise ImportError(
36 + "gRPC mode requires smg-grpc-servicer. "
37 + "If not installed, run: pip install vllm[grpc]. "
38 + "If already installed, there may be a broken import due to a "
39 + "version mismatch — see the chained exception above for details."
40 + ) from e
41 +
42 +import uvloop
43 +
44 +from vllm import envs
45 +from vllm.engine.arg_utils import AsyncEngineArgs
46 +from vllm.entrypoints.serve.utils.api_utils import log_version_and_model
47 +from vllm.logger import init_logger
48 +from vllm.usage.usage_lib import UsageContext
49 +from vllm.utils.argparse_utils import FlexibleArgumentParser
50 +from vllm.v1.engine.async_llm import AsyncLLM
51 +from vllm.version import __version__ as VLLM_VERSION
52 +
53 +logger = init_logger(__name__)
54 +
55 +
56 +async def serve_grpc(args: argparse.Namespace):
57 + """
58 + Main gRPC serving function.
59 +
60 + Args:
61 + args: Parsed command line arguments
62 + """
63 + log_version_and_model(logger, VLLM_VERSION, args.model)
64 + logger.info("vLLM gRPC server args: %s", args)
65 +
66 + start_time = time.time()
67 +
68 + # Create engine args
69 + engine_args = AsyncEngineArgs.from_cli_args(args)
70 +
71 + # Build vLLM config
72 + vllm_config = engine_args.create_engine_config(
73 + usage_context=UsageContext.OPENAI_API_SERVER,
74 + )
75 +
76 + # Create AsyncLLM
77 + async_llm = AsyncLLM.from_vllm_config(
78 + vllm_config=vllm_config,
79 + usage_context=UsageContext.OPENAI_API_SERVER,
80 + enable_log_requests=args.enable_log_requests,
81 + disable_log_stats=args.disable_log_stats,
82 + )
83 +
84 + # Create servicer
85 + servicer = VllmEngineServicer(async_llm, start_time)
86 +
87 + # Create gRPC server
88 + server = grpc.aio.server(
89 + options=[
90 + ("grpc.max_send_message_length", -1),
91 + ("grpc.max_receive_message_length", -1),
92 + # Tolerate client keepalive pings every 10s (default 300s is too
93 + # strict for non-streaming requests where no DATA frames flow
94 + # during generation)
95 + ("grpc.http2.min_recv_ping_interval_without_data_ms", 10000),
96 + ("grpc.keepalive_permit_without_calls", True),
97 + ],
98 + )
99 +
100 + # Add servicer to server
101 + vllm_engine_pb2_grpc.add_VllmEngineServicer_to_server(servicer, server)
102 +
103 + # Add standard gRPC health service for Kubernetes probes
104 + health_servicer = VllmHealthServicer(async_llm)
105 + health_pb2_grpc.add_HealthServicer_to_server(health_servicer, server)
106 +
107 + # Enable reflection for grpcurl and other tools
108 + service_names = (
109 + vllm_engine_pb2.DESCRIPTOR.services_by_name["VllmEngine"].full_name,
110 + "grpc.health.v1.Health",
111 + reflection.SERVICE_NAME,
112 + )
113 + reflection.enable_server_reflection(service_names, server)
114 +
115 + # Bind to address
116 + host = args.host or "0.0.0.0"
117 + address = f"{host}:{args.port}"
118 + server.add_insecure_port(address)
119 +
120 + try:
121 + # Start server
122 + await server.start()
123 + logger.info("vLLM gRPC server started on %s", address)
124 + logger.info("Server is ready to accept requests")
125 +
126 + # Start periodic stats logging (mirrors the HTTP server's lifespan task)
127 + if not args.disable_log_stats:
128 +
129 + async def _force_log():
130 + while True:
131 + await asyncio.sleep(envs.VLLM_LOG_STATS_INTERVAL)
132 + await async_llm.do_log_stats()
133 +
134 + stats_task = asyncio.create_task(_force_log())
135 + else:
136 + stats_task = None
137 +
138 + # Handle shutdown signals
139 + loop = asyncio.get_running_loop()
140 + stop_event = asyncio.Event()
141 +
142 + def signal_handler():
143 + logger.info("Received shutdown signal")
144 + stop_event.set()
145 +
146 + for sig in (signal.SIGTERM, signal.SIGINT):
147 + loop.add_signal_handler(sig, signal_handler)
148 +
149 + try:
150 + await stop_event.wait()
151 + except KeyboardInterrupt:
152 + logger.info("Interrupted by user")
153 + finally:
154 + logger.info("Shutting down vLLM gRPC server...")
155 + if stats_task is not None:
156 + stats_task.cancel()
157 + try:
158 + health_servicer.set_not_serving()
159 + except Exception: # broad: must not prevent server.stop() / shutdown()
160 + logger.warning("Failed to set health status to NOT_SERVING", exc_info=True)
161 + await server.stop(grace=5.0)
162 + logger.info("gRPC server stopped")
163 + async_llm.shutdown()
164 + logger.info("AsyncLLM engine stopped")
165 + logger.info("Shutdown complete")
166 +
167 +
168 +def main():
169 + """Main entry point for python -m vllm.entrypoints.launchers.grpc_server."""
170 + parser = FlexibleArgumentParser(
171 + description="vLLM gRPC Server",
172 + )
173 +
174 + # Server args
175 + parser.add_argument(
176 + "--host",
177 + type=str,
178 + default="0.0.0.0",
179 + help="Host to bind gRPC server to",
180 + )
181 + parser.add_argument(
182 + "--port",
183 + type=int,
184 + default=50051,
185 + help="Port to bind gRPC server to",
186 + )
187 + parser = AsyncEngineArgs.add_cli_args(parser)
188 +
189 + args = parser.parse_args()
190 +
191 + # Run server
192 + try:
193 + uvloop.run(serve_grpc(args))
194 + except Exception as e:
195 + logger.exception("Server failed: %s", e)
196 + sys.exit(1)
197 +
198 +
199 +if __name__ == "__main__":
200 + main()