From 1aa565a330169bec8b147a1b2b6e1c52da7ee07b Mon Sep 17 00:00:00 2001 From: Broque Thomas <26755000+Nezreka@users.noreply.github.com> Date: Thu, 30 Apr 2026 22:58:26 -0700 Subject: [PATCH] Silence shutdown-time logger errors so CI stderr stays clean Pytest tears down its log file handles before atexit runs. Every "Shutting down ..." line a worker emits while stopping then crashes Python's logger with "I/O operation on closed file" and floods CI stderr with --- Logging error --- traceback blocks. The CI sanity check workflow noticed once tests started importing web_server (the Tidal-auth integration test PR + this parallel-imports PR are the first two test files that boot the full module). Adds a tiny atexit handler that flips ``logging.raiseExceptions = False`` BEFORE the other shutdown handlers run. atexit's LIFO order makes "registered last" mean "runs first", so this fires ahead of cleanup_monitor / _atexit_shutdown / _atexit_save_history and any log calls those make can't bubble the closed-stream traceback. The shutdown messages themselves are best-effort debug breadcrumbs, not data we need to preserve at process exit, so silencing the internal handler errors costs nothing. --- web_server.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/web_server.py b/web_server.py index 46493063..ded6b72e 100644 --- a/web_server.py +++ b/web_server.py @@ -2941,9 +2941,25 @@ def _atexit_shutdown(): except Exception: pass + +def _atexit_silence_shutdown_logger_errors(): + # Pytest tears down log file handles before atexit fires, so every + # "Shutting down ..." line a worker emits while stopping crashes + # Python's logger with "I/O operation on closed file" and floods + # CI stderr. The messages themselves are best-effort debug + # breadcrumbs, not data we need to preserve at process exit. + # Registered last so atexit's LIFO order makes this run FIRST, + # ahead of cleanup_monitor / _atexit_shutdown / _atexit_save_history. + import logging as _logging + _logging.raiseExceptions = False + atexit.register(_atexit_save_history) atexit.register(_atexit_shutdown) atexit.register(cleanup_monitor) +# atexit runs in LIFO order — register the silencer LAST so it runs +# FIRST, before any other shutdown handler emits its "Shutting down" +# log line into a stream pytest already closed. +atexit.register(_atexit_silence_shutdown_logger_errors) signal.signal(signal.SIGINT, signal_handler) signal.signal(signal.SIGTERM, signal_handler)