systemd-socket-test (AI + Human)
  1. #!/usr/bin/env python3
  2. import asyncio
  3. import os
  4. import sys
  5. import socket
  6. import subprocess
  7. from pathlib import Path
  8. from textwrap import dedent
  9.  
  10. # =====================================================================
  11. # SYSTEMD TEMPLATE GENERATION FUNCTIONS (Modern Python Strings)
  12. # =====================================================================
  13.  
  14. SERVICE_UNIT = """
  15. [Unit]
  16. Description=Resilient Async Python Service (FD-Store)
  17. Requires={socket_name}
  18. After=network.target
  19.  
  20. [Service]
  21. Type=simple
  22. ExecStart={exec_path}
  23. Environment=PYTHONUNBUFFERED=1
  24.  
  25. # FD-Store and Recovery configurations
  26. FileDescriptorStoreMax=100
  27. Restart=on-failure
  28. RestartSec=0.1s
  29.  
  30. [Install]
  31. WantedBy=default.target
  32. """
  33.  
  34. SOCKET_UNIT = """[Unit]
  35. Description=Resilient Async Python Service Socket
  36.  
  37. [Socket]
  38. # Listens on localhost port {port} by default (ideal for user units)
  39. ListenStream={port}
  40.  
  41. [Install]
  42. WantedBy=sockets.target
  43. """
  44.  
  45.  
  46. def create_service_unit(socket_name: str, exec_path: str) -> str:
  47. """Generates the systemd service configuration using modern multi-line formatting."""
  48. return SERVICE_UNIT.format(socket_name=socket_name, exec_path=exec_path)
  49.  
  50.  
  51. def create_socket_unit(port: int = 8080) -> str:
  52. """Generates the systemd socket configuration."""
  53. return SOCKET_UNIT.format(port=port)
  54.  
  55.  
  56. # =====================================================================
  57. # SYSTEMD COMMAND HELPER
  58. # =====================================================================
  59.  
  60.  
  61. def run_systemctl_user(args: list) -> bool:
  62. """Helper function to safely run systemctl commands in user space."""
  63. try:
  64. cmd = ["systemctl", "--user"] + args
  65. print(f"Running: {' '.join(cmd)}")
  66. subprocess.run(cmd, check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
  67. return True
  68. except subprocess.CalledProcessError as e:
  69. print(
  70. f"[ERROR] systemctl command failed: {e.stderr.decode().strip()}",
  71. file=sys.stderr,
  72. )
  73. return False
  74.  
  75.  
  76. def resilient_accept(conn):
  77. send_fd_to_systemd(conn.fileno())
  78.  
  79.  
  80. # =====================================================================
  81. # INSTALLATION & DEINSTALLATION LOGIC
  82. # =====================================================================
  83.  
  84.  
  85. def install_systemd_user_units():
  86. """Automatically installs, enables, and starts the systemd user units."""
  87.  
  88. # human note:
  89. # Automatic installs are not good, if everything emerges from a single file.
  90. # The user doesn't know from where the file came and where it was installed.
  91. #
  92.  
  93. print("Initializing systemd user unit installation...")
  94.  
  95. # 1. Resolve structural paths
  96. script_path = Path(__file__).resolve()
  97. home_dir = Path.home()
  98.  
  99. # Standard systemd user configuration directory
  100. systemd_user_dir = home_dir / ".config" / "systemd" / "user"
  101.  
  102. service_file = systemd_user_dir / "async-resilient.service"
  103. socket_file = systemd_user_dir / "async-resilient.socket"
  104.  
  105. # 2. Ensure the configuration directories exist
  106. systemd_user_dir.mkdir(parents=True, exist_ok=True)
  107.  
  108. # 3. Generate unit contents via template functions
  109. service_content = create_service_unit(
  110. socket_name="async-resilient.socket", exec_path=str(script_path)
  111. )
  112. socket_content = create_socket_unit(port=8080)
  113.  
  114. # 4. Write unit configurations to disk
  115. try:
  116. service_file.write_text(service_content, encoding="utf-8")
  117. socket_file.write_text(socket_content, encoding="utf-8")
  118.  
  119. # Ensure the script itself remains executable
  120. # holy shit, the ai know octal notation!!!
  121. script_path.chmod(script_path.stat().st_mode | 0o755)
  122. print(f"[SUCCESS] Configurations written successfully.")
  123.  
  124. # 5. Execute systemd lifecycle commands automatically
  125. print("\nExecuting systemd lifecycle commands...")
  126. if run_systemctl_user(["daemon-reload"]):
  127. if run_systemctl_user(["enable", "async-resilient.socket"]):
  128. if run_systemctl_user(["start", "async-resilient.socket"]):
  129. print("\n[SUCCESS] Server socket is up and running via systemd!")
  130. print("You can now connect to port 8080.")
  131.  
  132. except Exception as e:
  133. print(f"[ERROR] Failed during systemd initialization: {e}", file=sys.stderr)
  134. sys.exit(1)
  135.  
  136.  
  137. def stop_and_disable_units():
  138. """Stops and disables the running systemd socket and service units."""
  139. print("Stopping and disabling systemd user units...")
  140.  
  141. # Stop the units first so connections drop cleanly
  142. run_systemctl_user(["stop", "async-resilient.service"])
  143. run_systemctl_user(["stop", "async-resilient.socket"])
  144.  
  145. # Disable them so they don't boot next time systemd starts
  146. run_systemctl_user(["disable", "async-resilient.socket"])
  147. run_systemctl_user(["disable", "async-resilient.service"])
  148.  
  149. # Reload daemon to clear out the state
  150. run_systemctl_user(["daemon-reload"])
  151. print("[SUCCESS] Units have been successfully stopped and disabled.")
  152.  
  153.  
  154. # =====================================================================
  155. # CORE NETWORK DAEMON LOGIC
  156. # =====================================================================
  157.  
  158.  
  159. def send_fd_to_systemd(fd: int):
  160. """Sends an active client File Descriptor to the systemd FD-Store."""
  161. notify_socket_path = os.environ.get("NOTIFY_SOCKET")
  162. if not notify_socket_path:
  163. return
  164.  
  165. if notify_socket_path.startswith("@"):
  166. notify_socket_path = "\x00" + notify_socket_path[1:]
  167.  
  168. try:
  169. with socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM) as sock:
  170. sock.connect(notify_socket_path)
  171. sock.sendmsg(
  172. [b"FDSTORE=1\n"],
  173. [
  174. (
  175. socket.SOL_SOCKET,
  176. socket.SCM_RIGHTS,
  177. int.to_bytes(fd, 4, sys.byteorder),
  178. )
  179. ],
  180. )
  181. except Exception as e:
  182. print(f"FD-Store Sync Error: {e}", file=sys.stderr)
  183.  
  184.  
  185. async def handle_client(
  186. reader: asyncio.StreamReader, writer: asyncio.StreamWriter, is_recovered=False
  187. ):
  188. """Asynchronously processes ongoing network clients."""
  189. try:
  190. addr = writer.get_extra_info("peername")
  191. print(f"Processing client from {addr} (Recovered: {is_recovered})")
  192.  
  193. if is_recovered:
  194. writer.write(
  195. b"Your server crashed, but asyncio recovered your connection flawlessly!\n"
  196. )
  197. await writer.drain()
  198. else:
  199. resilient_accept(writer.get_extra_info("socket"))
  200.  
  201. writer.write(b"Processing request... please wait 10 seconds.\n")
  202. await writer.drain()
  203. await asyncio.sleep(10)
  204. writer.write(b"Processing finished successfully.\n")
  205. await writer.drain()
  206. except Exception as e:
  207. print(f"Error handling client: {e}", file=sys.stderr)
  208. finally:
  209. writer.close()
  210. await writer.wait_closed()
  211.  
  212.  
  213. async def run_server():
  214. """Main daemon loop hooked into the systemd socket lifecycle."""
  215. listen_fds = os.environ.get("LISTEN_FDS")
  216. if not listen_fds:
  217. print(
  218. "Error: No systemd sockets passed down. Run 'init' or launch via systemd.socket.",
  219. file=sys.stderr,
  220. )
  221. sys.exit(1)
  222.  
  223. num_fds = int(listen_fds)
  224. print(f"Received {num_fds} total File Descriptors from systemd.")
  225.  
  226. # Main Listening Socket is always FD 3
  227. SYSTEMD_FIRST_FD = 3
  228. server_sock = socket.fromfd(SYSTEMD_FIRST_FD, socket.AF_INET, socket.SOCK_STREAM)
  229.  
  230. server = await asyncio.start_server(
  231. lambda r, w: asyncio.create_task(handle_client(r, w, is_recovered=False)),
  232. sock=server_sock,
  233. )
  234.  
  235. print("Async Server successfully bound and accepting connections...")
  236.  
  237. # Rehydrate any existing client connections (FD 4+) rescued from a previous crash
  238. if num_fds > 1:
  239. print(f"Resurrecting {num_fds - 1} surviving client connections...")
  240. for fd_num in range(4, 3 + num_fds):
  241. try:
  242. recovered_sock = socket.fromfd(
  243. fd_num, socket.AF_INET, socket.SOCK_STREAM
  244. )
  245. reader, writer = await asyncio.open_connection(sock=recovered_sock)
  246. asyncio.create_task(handle_client(reader, writer, is_recovered=True))
  247. except Exception as e:
  248. print(
  249. f"Failed to recover existing connection on FD {fd_num}: {e}",
  250. file=sys.stderr,
  251. )
  252.  
  253. async with server:
  254. await server.serve_forever()
  255.  
  256.  
  257. # =====================================================================
  258. # APPLICATION ENTRYPOINT
  259. # =====================================================================
  260.  
  261. if __name__ == "__main__":
  262. if len(sys.argv) > 1:
  263. action = sys.argv[1].lower()
  264. if action == "init":
  265. install_systemd_user_units()
  266. elif action == "stop":
  267. stop_and_disable_units()
  268. else:
  269. print(
  270. f"Unknown argument: '{sys.argv[1]}'. Use 'init' or 'stop'.",
  271. file=sys.stderr,
  272. )
  273. else:
  274. try:
  275. asyncio.run(run_server())
  276. except KeyboardInterrupt:
  277. print("\nServer shutting down gracefully.")
  278.  
Pasted 2026-10-10 00:00:00

Short link: