pub struct GrpcDispatcher { /* private fields */ }Expand description
gRPC dispatcher that routes A2A requests to a RequestHandler.
Serves the canonical lf.a2a.v1.A2AService (protobuf-native, wire
compatible with the official A2A SDKs). That is the only gRPC surface:
the deprecated pre-0.7 JSON-tunnel service, and the grpc-legacy-json
feature that gated it, were removed in 0.8.
Create via GrpcDispatcher::new and serve with GrpcDispatcher::serve
or build a tonic service with GrpcDispatcher::into_service.
Implementations§
Source§impl GrpcDispatcher
impl GrpcDispatcher
Sourcepub const fn new(handler: Arc<RequestHandler>, config: GrpcConfig) -> Self
pub const fn new(handler: Arc<RequestHandler>, config: GrpcConfig) -> Self
Creates a new gRPC dispatcher wrapping the given handler.
Sourcepub const fn with_http2_keepalive(
self,
interval: Duration,
timeout: Duration,
) -> Self
pub const fn with_http2_keepalive( self, interval: Duration, timeout: Duration, ) -> Self
Sends an HTTP/2 PING every interval on an idle connection and closes
it if no answer arrives within timeout. Default: off.
GrpcConfig bounds message size and per-connection concurrency, and
nothing bounded a connection that is simply there. MEASURED
2026-08-19: 400 TCP connections opened against this dispatcher and left
silent were all accepted and all still alive twelve seconds later. The
ceiling is the process’s file-descriptor table — the same measurement,
and the same shape, as the WebSocket dispatcher before
with_idle_timeout.
HTTP/2 keepalive is the gRPC-native answer to it, and it is better than a plain idle timeout for the same reason the WebSocket knob pings: a conformant client’s HTTP/2 stack answers a PING without the application being involved, so this closes peers that are unresponsive rather than peers that are merely quiet. A streaming RPC that is waiting for its next event is quiet and healthy, and this leaves it alone.
Off by default, matching this workspace’s other connection knobs: a
deployment may have clients that are configured to object to PINGs, and
choosing an interval for someone is choosing their traffic profile.
(Duration::from_secs(30), Duration::from_secs(10)) is a conventional
starting point.
Sourcepub const fn with_max_connection_age(self, age: Duration) -> Self
pub const fn with_max_connection_age(self, age: Duration) -> Self
Closes a connection once it has been open for age, letting the client
reconnect. Default: off.
Distinct from with_http2_keepalive,
which detects a peer that has stopped answering. This one bounds a peer
that answers perfectly and simply never leaves — which is what makes a
fleet behind a load balancer drift into imbalance, since a gRPC client
pins one connection and keeps it.
tonic sends GOAWAY and drains in-flight RPCs rather than cutting them, so this is a reconnect rather than a failure.
Sourcepub async fn serve(self, addr: impl ToSocketAddrs) -> Result<()>
pub async fn serve(self, addr: impl ToSocketAddrs) -> Result<()>
Starts a gRPC server on the given address.
Blocks until the server shuts down. Uses the configured message size limits and concurrency settings.
§Errors
Returns std::io::Error if binding fails.
Sourcepub async fn serve_with_addr(
self,
addr: impl ToSocketAddrs,
) -> Result<SocketAddr>
pub async fn serve_with_addr( self, addr: impl ToSocketAddrs, ) -> Result<SocketAddr>
Starts a gRPC server and returns the bound SocketAddr.
Like serve, but returns the address immediately
and runs the server in a background task. Useful for tests.
§Errors
Returns std::io::Error if binding fails.
Sourcepub fn serve_with_listener(self, listener: TcpListener) -> Result<SocketAddr>
pub fn serve_with_listener(self, listener: TcpListener) -> Result<SocketAddr>
Starts a gRPC server on a pre-bound TcpListener.
This is the recommended approach when you need to know the server address before constructing the handler (e.g., for agent cards with correct URLs). Pre-bind the listener, extract the address, build your handler, then pass the listener here.
Returns the local address and runs the server in a background task.
§Errors
Returns std::io::Error if the listener’s local address cannot be read.
Sourcepub fn into_service(&self) -> A2aServiceServer<A2aServiceImpl>
pub fn into_service(&self) -> A2aServiceServer<A2aServiceImpl>
Builds the canonical tonic service for use with a custom server setup.
Returns an A2aServiceServer (the lf.a2a.v1.A2AService binding)
that can be added to a tonic::transport::Server via add_service.
It is the only gRPC service this dispatcher serves; the pre-0.7
JSON-tunnel companion was removed in 0.8.
Trait Implementations§
Auto Trait Implementations§
impl !RefUnwindSafe for GrpcDispatcher
impl !UnwindSafe for GrpcDispatcher
impl Freeze for GrpcDispatcher
impl Send for GrpcDispatcher
impl Sync for GrpcDispatcher
impl Unpin for GrpcDispatcher
impl UnsafeUnpin for GrpcDispatcher
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> FutureExt for T
impl<T> FutureExt for T
Source§fn with_context(self, otel_cx: Context) -> WithContext<Self> ⓘ
fn with_context(self, otel_cx: Context) -> WithContext<Self> ⓘ
Source§fn with_current_context(self) -> WithContext<Self> ⓘ
fn with_current_context(self) -> WithContext<Self> ⓘ
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§impl<T> IntoRequest<T> for T
impl<T> IntoRequest<T> for T
Source§fn into_request(self) -> Request<T>
fn into_request(self) -> Request<T>
T in a tonic::Request