Skip to content

[Feature Request] Support systemd Socket Activation (LISTEN_FDS) #786

@wordhui

Description

@wordhui

Hi! First of all, thank you for spending your valuable personal time building Granian — it’s an excellent high-performance piece of software.

I’d like to propose adding support for systemd Socket Activation to Granian.

Background & Motivation

In single-host deployments, a common approach to achieve “zero downtime” restarts is to rely on SIGHUP-based reloads. However, a pure reload mechanism has limitations in the following cases, because it typically reuses the same master process:

  1. Environment variable updates: systemd Environment= values are usually injected only when the process starts. When systemctl reload sends a signal to the main process, the PID stays the same, so the process won’t pick up changes made to environment variables in the unit file.
  2. Binary / dependency updates: When upgrading Granian itself, critical dependencies (e.g., uvloop), or even a Python patch version (e.g., 3.13.0 -> 3.13.1), it’s hard to be confident the updated libraries are actually loaded unless the process is fully restarted.

Proposed Solution

systemd Socket Activation is a best-practice solution for the issues above, especially for cost-effective single-host deployments. It doesn’t require an external load balancer; it only depends on systemd, yet can deliver production-grade high availability:

  • Truly smooth restarts: systemctl restart starts a completely new process. During the transition, systemd holds the listening socket and queues incoming connections (so instead of “Connection refused”, clients typically experience a brief delay) until the new process takes over.
  • Strong isolation: Each restart launches a fresh process, which cleanly solves both environment refresh and dependency upgrade concerns.

Notably, many popular Python WSGI/ASGI servers (e.g., Gunicorn, uWSGI, Hypercorn, Uvicorn) already support this deployment model, and it has been widely proven as a standard and reliable production practice.

Feasibility Notes

I took a quick look at Granian’s source code, and it seems the underlying Rust implementation may already have the necessary building blocks,
Unfortunately, I'm not yet capable of finishing the changes required for the PR, so I haven't submitted it."
In src/net.rs, the SocketHolder type already exposes a constructor that can initialize from an existing file descriptor (FD):

#[cfg(any(target_os = "linux", target_os = "freebsd"))]
#[pymethods]
impl SocketHolder {
    #[new]
    pub fn new(fd: i32, uds: bool, backlog: i32) -> Self {
        let socket = unsafe { Socket::from_raw_fd(fd) };
        // ...
    }
}

This suggests the Rust backend can already accept a pre-opened socket. If the Python-side initialization logic (e.g., granian/server/common.py) could detect the LISTEN_FDS environment variable and pass the corresponding FD(s) into SocketHolder, it might be possible to implement socket activation with relatively small changes (based on my limited understanding).

If Granian could start by inheriting systemd-provided file descriptors, it would significantly improve production usability.

(If anything above is incorrect, I’m sorry — some of this text was produced with the help of a translation tool and may be a bit rough.)
Thanks again for your great work!

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions