Claude commited on
Commit
4585786
·
unverified ·
1 Parent(s): e37f216

fix(ci): désactive le tqdm monitor thread (flake Python 3.12 ubuntu)

Browse files

Le combo ``tqdm._monitor`` + ``ProcessPoolExecutor`` (utilisé par
``picarones.measurements.runner.orchestration`` pour les moteurs
CPU-bound : Tesseract, Pero OCR) provoque un hang du shutdown de
l'interpréteur Python 3.12+ sur ubuntu-latest. Le
``_python_exit`` de ``concurrent.futures.process`` essaie de
joindre les workers du pool, mais le thread monitor non-daemon
de tqdm bloque la sortie globale → hang qui dépasse le timeout
GNU configuré dans ci.yml (9 min) → exit code 124 et job en
failure.

Stack trace observée systématiquement :

File "tqdm/_monitor.py", line 60 in run
File "concurrent/futures/process.py", line 587 in _join_executor_internals
File "concurrent/futures/process.py", line 106 in _python_exit
File "threading.py", line 1594 in _shutdown
Error: Process completed with exit code 124.

Fix : ``tqdm.monitor_interval = 0`` dans ``tests/conftest.py``,
exécuté avant tout import de ``picarones.measurements.runner``.
Le polling thread de tqdm n'a aucune valeur ajoutée en CI (stdout
captured, pas d'affichage interactif) — le désactiver supprime la
contention avec le shutdown de ``ProcessPoolExecutor``.

C'est l'approche standard pour ce flake spécifique sur tqdm +
multiprocessing (cf. issues récurrentes du projet tqdm sur
Python 3.12+).

Vérifications
-------------
- ``pytest tests/`` : 5004 passed, 0 failed (identique au baseline)
- ``ruff check tests/conftest.py`` : clean
- Le ``pytest_sessionfinish`` existant (qui détecte les threads
stuck via ``faulthandler.dump_traceback_later(60)``) continue de
fonctionner — il loggera tout futur thread non-daemon qui fuit.

https://claude.ai/code/session_011XQZNitg1rCgia8ZD1a2hP

Files changed (1) hide show
  1. tests/conftest.py +25 -0
tests/conftest.py CHANGED
@@ -49,6 +49,31 @@ os.environ.pop("PICARONES_PUBLIC_MODE", None)
49
  os.environ.setdefault("PICARONES_RATE_LIMIT_PER_HOUR", "0")
50
 
51
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
52
  def pytest_sessionfinish(session, exitstatus) -> None: # noqa: ARG001
53
  """Diagnostic du shutdown de l'interpréteur.
54
 
 
49
  os.environ.setdefault("PICARONES_RATE_LIMIT_PER_HOUR", "0")
50
 
51
 
52
+ # (3) Désactivation préventive du thread daemon de tqdm.
53
+ # Sur Python 3.12+ (ubuntu-latest en CI), le combo
54
+ # ``tqdm._monitor`` + ``ProcessPoolExecutor`` (utilisé par
55
+ # ``picarones.measurements.runner.orchestration`` pour les moteurs
56
+ # CPU-bound : Tesseract, Pero OCR) provoque un hang du shutdown de
57
+ # l'interpréteur après ``=== passed ===``. Le ``_python_exit`` de
58
+ # ``concurrent.futures.process`` essaie de joindre les workers du
59
+ # pool, mais le thread monitor de tqdm bloque la sortie globale —
60
+ # le hang dépasse le timeout GNU configuré dans ci.yml (9 min) et
61
+ # le job échoue avec exit code 124.
62
+ #
63
+ # ``monitor_interval=0`` désactive le polling thread de tqdm, qui
64
+ # n'est utile qu'à l'affichage interactif des progress bars (sans
65
+ # valeur ajoutée en CI où stdout est captured). Fix idiomatique
66
+ # pour ce flake spécifique.
67
+ try:
68
+ from tqdm import tqdm as _tqdm
69
+
70
+ _tqdm.monitor_interval = 0
71
+ except ImportError: # pragma: no cover
72
+ # tqdm est une dep de prod (cf. pyproject.toml) ; cette branche
73
+ # ne devrait jamais être atteinte en CI mais reste défensive.
74
+ pass
75
+
76
+
77
  def pytest_sessionfinish(session, exitstatus) -> None: # noqa: ARG001
78
  """Diagnostic du shutdown de l'interpréteur.
79