[gRPC] Native gRPC server: proto + Rust crate scaffold + server args (#22736)
This commit is contained in:
@@ -0,0 +1,39 @@
|
||||
[package]
|
||||
name = "sglang-grpc"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
description = "In-process Rust gRPC server for SGLang"
|
||||
license = "Apache-2.0"
|
||||
|
||||
[lib]
|
||||
name = "_core"
|
||||
crate-type = ["cdylib"]
|
||||
|
||||
[dependencies]
|
||||
pyo3 = { version = "0.23", features = ["extension-module"] }
|
||||
tokio = { version = "1", features = ["full"] }
|
||||
tonic = { version = "0.12", features = ["gzip", "transport"] }
|
||||
prost = "0.13"
|
||||
crossbeam-channel = "0.5"
|
||||
uuid = { version = "1", features = ["v4"] }
|
||||
tracing = "0.1"
|
||||
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
|
||||
serde_json = "1"
|
||||
tokenizers = { version = "0.21", default-features = false, features = ["onig"] }
|
||||
tokio-stream = "0.1"
|
||||
async-stream = "0.3"
|
||||
|
||||
[build-dependencies]
|
||||
tonic-build = "0.12"
|
||||
|
||||
[features]
|
||||
default = ["pyo3/extension-module"]
|
||||
|
||||
[profile.release]
|
||||
opt-level = 2
|
||||
lto = "thin"
|
||||
strip = true
|
||||
|
||||
[profile.dev]
|
||||
opt-level = 0
|
||||
debug = 1
|
||||
@@ -0,0 +1,15 @@
|
||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let proto_path = "../../proto/sglang/runtime/v1/sglang.proto";
|
||||
|
||||
tonic_build::configure()
|
||||
.build_server(true)
|
||||
.build_client(false)
|
||||
.file_descriptor_set_path(
|
||||
std::path::PathBuf::from(std::env::var("OUT_DIR").unwrap())
|
||||
.join("sglang_descriptor.bin"),
|
||||
)
|
||||
.compile_protos(&[proto_path], &["../../proto"])?;
|
||||
|
||||
println!("cargo:rerun-if-changed={}", proto_path);
|
||||
Ok(())
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
use pyo3::prelude::*;
|
||||
use std::sync::Arc;
|
||||
use tokio::sync::Notify;
|
||||
|
||||
pub mod proto {
|
||||
tonic::include_proto!("sglang.runtime.v1");
|
||||
}
|
||||
|
||||
/// Handle returned by `start_server` — used to shut down the gRPC server.
|
||||
#[pyclass]
|
||||
pub struct GrpcServerHandle {
|
||||
shutdown: Arc<Notify>,
|
||||
join_handle: Option<std::thread::JoinHandle<()>>,
|
||||
}
|
||||
|
||||
#[pymethods]
|
||||
impl GrpcServerHandle {
|
||||
/// Signal the server to stop and wait for the background thread to exit.
|
||||
fn shutdown(&mut self) {
|
||||
self.shutdown.notify_one();
|
||||
if let Some(handle) = self.join_handle.take() {
|
||||
let _ = handle.join();
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `true` while the server thread is still running.
|
||||
fn is_alive(&self) -> bool {
|
||||
self.join_handle
|
||||
.as_ref()
|
||||
.map_or(false, |h| !h.is_finished())
|
||||
}
|
||||
}
|
||||
|
||||
/// Start the gRPC server in a background thread.
|
||||
///
|
||||
/// * `host` – bind address (e.g. "0.0.0.0")
|
||||
/// * `port` – listen port
|
||||
/// * `runtime_handle` – Python `RuntimeHandle` object (from `grpc_bridge.py`)
|
||||
///
|
||||
/// Returns a `GrpcServerHandle` that can be used to shut the server down.
|
||||
#[pyfunction]
|
||||
fn start_server(host: String, port: u16, runtime_handle: PyObject) -> PyResult<GrpcServerHandle> {
|
||||
let _ = &runtime_handle; // Will be used in Phase 1 PR 2
|
||||
let shutdown = Arc::new(Notify::new());
|
||||
let shutdown_clone = shutdown.clone();
|
||||
|
||||
let addr_str = format!("{}:{}", host, port);
|
||||
let addr: std::net::SocketAddr = addr_str
|
||||
.parse()
|
||||
.map_err(|e| pyo3::exceptions::PyValueError::new_err(format!("Bad address: {e}")))?;
|
||||
|
||||
let join_handle = std::thread::Builder::new()
|
||||
.name("grpc-server".into())
|
||||
.spawn(move || {
|
||||
let rt = tokio::runtime::Builder::new_multi_thread()
|
||||
.worker_threads(4)
|
||||
.enable_all()
|
||||
.build()
|
||||
.expect("Failed to build Tokio runtime");
|
||||
|
||||
rt.block_on(async move {
|
||||
tracing::info!("gRPC server listening on {}", addr);
|
||||
// Server implementation will be added in PR 2.
|
||||
// For now, just wait for shutdown signal.
|
||||
shutdown_clone.notified().await;
|
||||
tracing::info!("gRPC server shutting down");
|
||||
});
|
||||
})
|
||||
.map_err(|e| {
|
||||
pyo3::exceptions::PyRuntimeError::new_err(format!("Failed to spawn thread: {e}"))
|
||||
})?;
|
||||
|
||||
Ok(GrpcServerHandle {
|
||||
shutdown,
|
||||
join_handle: Some(join_handle),
|
||||
})
|
||||
}
|
||||
|
||||
/// Python module exported by the Rust extension.
|
||||
#[pymodule]
|
||||
fn _core(m: &Bound<'_, PyModule>) -> PyResult<()> {
|
||||
m.add_function(wrap_pyfunction!(start_server, m)?)?;
|
||||
m.add_class::<GrpcServerHandle>()?;
|
||||
Ok(())
|
||||
}
|
||||
Reference in New Issue
Block a user