2nd iteration fix socket activation

This commit is contained in:
2025-12-03 22:45:28 +01:00
parent 94b1730c24
commit c9d4b636e6

View File

@@ -47,29 +47,30 @@ from middleware.cache_middleware import cache_control
# Helper -------------------------------------------------------------------- # Helper --------------------------------------------------------------------
def _fd_to_socket(fd: int) -> socket.socket: def _fd_to_socket(fd: int) -> socket.socket:
""" """
Turn a raw filedescriptor that came from systemd into a *nonblocking* Convert a filedescriptor received from systemd into a readytouse
``socket.socket`` instance that preserves the original family, type and ``socket.socket`` object.
protocol.
The function mirrors the logic used by `sd_listen_fds` in the systemd * The fd already contains the correct address family, socket type and
libraries (see libsystemd/libsystemd/sd-daemon.c). It queries the protocol passing ``fileno=fd`` makes the constructor adopt them.
kernel for the socket's actual family, type and protocol using * aiohttp (and the rest of the code) expects the socket to be **nonblocking**,
``getsockopt`` on the fd. so we set that flag explicitly.
* Any OSError while wrapping the descriptor is turned into a RuntimeError
with a clear message; the caller can log it.
""" """
# Query the kernel for the family / type / protocol of the fd. try:
# These syscalls are cheap and work for IPv4, IPv6 and Unix sockets. # ``socket.socket`` with the ``fileno`` argument reuses the existing OS
family = socket.getsockopt(fd, socket.SOL_SOCKET, socket.SO_DOMAIN) # socket. The resulting object automatically reports the correct
sock_type = socket.getsockopt(fd, socket.SOL_SOCKET, socket.SO_TYPE) # ``family``, ``type`` and ``proto`` attributes.
proto = socket.getsockopt(fd, socket.SOL_SOCKET, socket.SO_PROTOCOL) sock = socket.socket(fileno=fd)
# Build the socket object *without* creating a new fd. # aiohttps SockSite registers the socket with the event loop, which
# ``socket.socket`` with ``fileno=fd`` reuses the existing descriptor. # requires a nonblocking descriptor.
# ``closefd=False`` tells Python not to close the fd when the socket sock.setblocking(False)
# object is garbagecollected systemd will close it when the service
# exits. return sock
sock = socket.socket(family=family, type=sock_type, proto=proto, fileno=fd) except OSError as exc:
sock.setblocking(False) # aiohttp expects nonblocking # Raising a RuntimeError makes the callers ``except`` clause simpler.
return sock raise RuntimeError(f"Could not wrap fd {fd} as a socket: {exc}") from exc
async def send_socket_catch_exception(function, message): async def send_socket_catch_exception(function, message):
try: try: