#2733·grpc-rust

Add socket-activation support for grpc.

Author: AndreeaDrehutaCreated Jul 14, 2026Updated Sep 15, 2026

Feature Request

Crates

tonic (transport server: TcpIncoming / UnixIncoming), behind a new opt-in socket-activation cargo feature. Unix-only.

Motivation

Under systemd, a service can be started on-demand when a client connects. The manager creates and listens on the socket itself, then passes the already-listening file descriptor to the spawned process via the LISTEN_FDS / LISTEN_PID environment variables.

Consider a gRPC server that receives requests only occasionally. Keeping it running around the clock just to answer the rare request wastes memory and other resources. A better fit for that situation is to let the process run only while it is actually serving requests: the service manager (systemd) holds the socket, starts the server on an incoming connection, and the server can stop itself once it goes idle, after which the manager re-activates it on the next connection.

This enables:

  • Lazy startup / on-demand activation - the server process only runs when there is actual traffic.
  • Zero-downtime restarts - the listening socket outlives the process, so connections established during a restart are not refused.

Today a tonic server always calls bind() itself, so it cannot participate in socket activation.

Proposal

Add an opt-in socket-activation cargo feature (Unix-only). When enabled, TcpIncoming::bind and UnixIncoming::bind first check whether a matching listening descriptor was passed in via LISTEN_FDS / LISTEN_PID`:

  • Validate LISTEN_PID matches the current process id.
  • Scan the inherited descriptors (SD_LISTEN_FDS_START = 3 onward), verifying each is a listening stream socket.
  • Match by requested address (TCP, treating IPv4-mapped and wildcard binds as equal) or by socket path (UDS).
  • Adopt the matching fd instead of binding a fresh socket; otherwise fall back to the normal bind().

The feature is off by default, so behavior is unchanged unless explicitly enabled.

Alternatives

Do it in user code - the application reads LISTEN_FDS and constructs a listener, passing it via serve_with_incoming. This works but forces every user to re-implement the sd_listen_fds protocol (pid check, fd scanning, socket-type validation, address matching) correctly. Baking it into the transport makes the common case a one-line, feature-gated opt-in.

  • libsystemd / sd-listen-fds crate dependency - pulls in an extra (often C-linked) dependency for a small, well-specified protocol. The proposed implementation needs only socket2, which tonic already uses.