Skip to main content

Vine/Server/
SpawnBindTaskWithShutdown.rs

1//! Spawn a detached tokio task that serves a tonic gRPC `Router` with
2//! graceful shutdown signalling.
3//!
4//! Uses `tonic::transport::Server::serve_with_shutdown(...)` so daemon-
5//! style embedders can drain in-flight RPCs before exiting. The simpler
6//! [`crate::Server::SpawnBindTask::Fn`] runs without a shutdown signal;
7//! both shapes are kept side-by-side so embedders pick whichever matches
8//! their lifecycle model.
9//!
10//! ## Lifecycle
11//!
12//! - The task runs until `ShutdownSignal` resolves OR the OS socket closes.
13//! - On `Ok(())` exit, dev_log marks clean shutdown.
14//! - On `Err`, dev_log captures the transport error.
15//!
16//! ## Choosing between the two helpers
17//!
18//! | Need                                  | Helper                            |
19//! | ------------------------------------- | --------------------------------- |
20//! | Serve until process termination       | `SpawnBindTask`                   |
21//! | Serve until a signal fires (recommended for daemons) | `SpawnBindTaskWithShutdown` |
22
23use std::{future::Future, net::SocketAddr};
24
25use tonic::transport::server::Router;
26
27use crate::dev_log;
28
29/// Spawn a detached tokio task that serves `Router` on `Address` until
30/// `ShutdownSignal` resolves.
31///
32/// # Parameters
33///
34/// * `ServerName`      - label used in dev-log messages.
35/// * `Address`         - resolved socket address (callers should run
36///   [`crate::Server::ValidateSocketAddress::Fn`] first).
37/// * `Router`          - constructed tonic Router with services already added.
38/// * `ShutdownSignal`  - any `Future<Output = ()> + Send + 'static`. When it
39///   resolves, the server gracefully stops accepting new connections and drains
40///   in-flight calls.
41pub fn Fn<S>(ServerName:String, Address:SocketAddr, Router:Router, ShutdownSignal:S)
42where
43	S: Future<Output = ()> + Send + 'static, {
44	tokio::spawn(async move {
45		dev_log!(
46			"grpc",
47			"[Vine::Server] Starting {} gRPC server on {} (with shutdown signal)",
48			ServerName,
49			Address
50		);
51
52		let Result_ = Router.serve_with_shutdown(Address, ShutdownSignal).await;
53
54		match Result_ {
55			Ok(_) => {
56				dev_log!("grpc", "[Vine::Server] {} server stopped cleanly", ServerName);
57			},
58
59			Err(Error) => {
60				dev_log!("grpc", "error: [Vine::Server] {} gRPC server error: {}", ServerName, Error);
61			},
62		}
63	});
64}