Skip to content

Add socket-activation support for grpc. #2733

Description

@AndreeaDrehuta

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions