[Rust Frontend] Improve startup failure and readiness logs (#50406)
Signed-off-by: Bugen Zhao <i@bugenzhao.com> Co-authored-by: OpenAI Codex <codex@openai.com>
Bugen Zhao committed
Jul 31, 2026 at 05:18 UTC
e9096fcb123181467a6fff5326fe8387d578760c
2 files changed
+39
-12
rust/src/cmd/src/main.rs
+15
-6
@@ -5,11 +5,12 @@ mod cli;
5
6
use std::env;
7
use std::ffi::OsStr;
8
-use std::process::ExitStatus;
8
+use std::process::{ExitCode, ExitStatus};
9
10
use anyhow::{Context, Result, anyhow, bail};
11
+use thiserror_ext::AsReport as _;
12
use tokio_util::sync::CancellationToken;
12
-use tracing::{info, warn};
13
+use tracing::{error, info, warn};
14
use vllm_managed_engine::ManagedEngineHandle;
15
16
use crate::cli::{BenchCommand, Cli, Command};
@@ -81,7 +82,7 @@ fn shutdown_signal() -> CancellationToken {
82
token
83
}
84
84
-fn main() -> Result<()> {
85
+fn main() -> ExitCode {
86
let process_label =
87
match env::args_os().nth(1).as_deref().and_then(OsStr::to_str).unwrap_or_default() {
88
"bench" => "Bench",
@@ -98,10 +99,18 @@ fn main() -> Result<()> {
99
runtime.worker_threads(worker_threads);
100
}
101
101
- runtime
102
+ let result = runtime
103
.build()
103
- .context("failed to build Tokio runtime")?
104
- .block_on(async_main(cli))
104
+ .context("failed to build Tokio runtime")
105
+ .and_then(|runtime| runtime.block_on(async_main(cli)));
106
+
107
+ match result {
108
+ Ok(()) => ExitCode::SUCCESS,
109
+ Err(error) => {
110
+ error!("process failed with error: {:#?}", error.as_report());
111
+ ExitCode::FAILURE
112
+ }
113
+ }
114
}
115
116
async fn async_main(cli: Cli) -> Result<()> {
rust/src/server/src/lib.rs
+24
-6
@@ -181,12 +181,15 @@ where
181
result = build_state(&config) => result?,
182
_ = shutdown.cancelled() => return Ok(()),
183
};
184
+ let model = state.primary_model_name().to_owned();
185
+ let app = extend_router(build_router(state.clone()));
186
+
187
+ info!(model, "starting vLLM server");
188
+
189
let listener = Listener::bind(&config.listener_mode)
190
.await
191
.context("failed to bind listener for OpenAI server")?;
192
let bind_address = listener.local_addr_display()?;
188
- let model = state.primary_model_name().to_owned();
189
- let app = extend_router(build_router(state.clone()));
193
194
// Optionally bind the gRPC Inference server on a separate port. Bind
195
// synchronously here so bind errors (port in use, permission denied, ...)
@@ -220,8 +223,14 @@ where
223
.add_service(health_service)
224
.add_service(control_service)
225
.add_service(inference_service);
223
- info!(%addr, tls = grpc_tls.is_some(), "starting gRPC server");
224
- Some((grpc_listener, svc, grpc_tls, health_reporter, engine_health))
226
+ Some((
227
+ addr,
228
+ grpc_listener,
229
+ svc,
230
+ grpc_tls,
231
+ health_reporter,
232
+ engine_health,
233
+ ))
234
} else {
235
None
236
};
@@ -231,7 +240,7 @@ where
240
} else {
241
"http"
242
};
234
- info!(%bind_address, %scheme, %model, "starting OpenAI server");
243
+ let model = model.as_str();
244
245
// Run HTTP and gRPC concurrently under a child token of the caller's shutdown
246
// token. Caller cancellation propagates into both protocols; if either
@@ -285,6 +294,11 @@ where
294
};
295
let server = serve_connections(listener, app, shutdown.cancelled_owned(), timeouts);
296
297
+ info!(
298
+ bind_address,
299
+ scheme, model, "OpenAI server is ready to accept requests"
300
+ );
301
+
302
let result = tokio::select! {
303
result = server => {
304
result.context("HTTP server failed")
@@ -305,13 +319,15 @@ where
319
let server_shutdown = server_shutdown.clone();
320
let force_shutdown = force_shutdown.clone();
321
async move {
308
- let Some((grpc_listener, svc, grpc_tls, health_reporter, engine_health)) = grpc_setup
322
+ let Some((addr, grpc_listener, svc, grpc_tls, health_reporter, engine_health)) =
323
+ grpc_setup
324
else {
325
// No gRPC configured: just wait for shutdown so we do not race the
326
// join! by resolving early and tripping the cancellation token.
327
shutdown.cancelled().await;
328
return Ok(());
329
};
330
+ let tls = grpc_tls.is_some();
331
let incoming = match grpc_tls {
332
Some(context) => MaybeTlsListener::tls(grpc_listener, context),
333
None => MaybeTlsListener::plain(grpc_listener),
@@ -320,6 +336,8 @@ where
336
svc.serve_with_incoming_shutdown(incoming, shutdown.clone().cancelled_owned());
337
let health_monitor = grpc::monitor_health(health_reporter, engine_health, shutdown);
338
339
+ info!(%addr, tls, model, "gRPC server is ready to accept requests");
340
+
341
let server = async move {
342
let result = tokio::select! {
343
result = server => {