2nd iteration fix socket activation
This commit is contained in:
41
server.py
41
server.py
@@ -47,29 +47,30 @@ from middleware.cache_middleware import cache_control
|
||||
# Helper --------------------------------------------------------------------
|
||||
def _fd_to_socket(fd: int) -> socket.socket:
|
||||
"""
|
||||
Turn a raw file‑descriptor that came from systemd into a *non‑blocking*
|
||||
``socket.socket`` instance that preserves the original family, type and
|
||||
protocol.
|
||||
Convert a file‑descriptor received from systemd into a ready‑to‑use
|
||||
``socket.socket`` object.
|
||||
|
||||
The function mirrors the logic used by `sd_listen_fds` in the systemd
|
||||
libraries (see libsystemd/libsystemd/sd-daemon.c). It queries the
|
||||
kernel for the socket's actual family, type and protocol using
|
||||
``getsockopt`` on the fd.
|
||||
* The fd already contains the correct address family, socket type and
|
||||
protocol – passing ``fileno=fd`` makes the constructor adopt them.
|
||||
* aiohttp (and the rest of the code) expects the socket to be **non‑blocking**,
|
||||
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.
|
||||
# These syscalls are cheap and work for IPv4, IPv6 and Unix sockets.
|
||||
family = socket.getsockopt(fd, socket.SOL_SOCKET, socket.SO_DOMAIN)
|
||||
sock_type = socket.getsockopt(fd, socket.SOL_SOCKET, socket.SO_TYPE)
|
||||
proto = socket.getsockopt(fd, socket.SOL_SOCKET, socket.SO_PROTOCOL)
|
||||
try:
|
||||
# ``socket.socket`` with the ``fileno`` argument re‑uses the existing OS
|
||||
# socket. The resulting object automatically reports the correct
|
||||
# ``family``, ``type`` and ``proto`` attributes.
|
||||
sock = socket.socket(fileno=fd)
|
||||
|
||||
# Build the socket object *without* creating a new fd.
|
||||
# ``socket.socket`` with ``fileno=fd`` re‑uses the existing descriptor.
|
||||
# ``closefd=False`` tells Python not to close the fd when the socket
|
||||
# object is garbage‑collected – systemd will close it when the service
|
||||
# exits.
|
||||
sock = socket.socket(family=family, type=sock_type, proto=proto, fileno=fd)
|
||||
sock.setblocking(False) # aiohttp expects non‑blocking
|
||||
return sock
|
||||
# aiohttp’s SockSite registers the socket with the event loop, which
|
||||
# requires a non‑blocking descriptor.
|
||||
sock.setblocking(False)
|
||||
|
||||
return sock
|
||||
except OSError as exc:
|
||||
# Raising a RuntimeError makes the caller’s ``except`` clause simpler.
|
||||
raise RuntimeError(f"Could not wrap fd {fd} as a socket: {exc}") from exc
|
||||
|
||||
async def send_socket_catch_exception(function, message):
|
||||
try:
|
||||
|
||||
Reference in New Issue
Block a user