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.
pull/456/head
Broque Thomas 4 weeks ago
parent f339211654
commit 1aa565a330

@ -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)

Loading…
Cancel
Save