Spaces:
Sleeping
chore(7.C): retire l'instrumentation ProcessPoolExecutor du conftest
Browse filesLe monkey-patch d'investigation introduit dans le commit 78846f6
(PR #59) avait servi à identifier la cause racine du hang
``_python_exit`` sur Python 3.12 ubuntu (les tests web qui chargent
un vrai ``TesseractEngine`` via ``engine_from_name``). La cause
ayant été trouvée et fixée à la source dans
``picarones/measurements/runner/orchestration.py``, l'instrumentation
n'a plus de raison d'être.
Le commentaire du commit 78846f6 disait explicitement :
Le monkey-patch d'instrumentation est conservé dans
``tests/conftest.py`` jusqu'à confirmation que la CI Ubuntu 3.12
passe désormais. À retirer dans un commit séparé une fois la
preuve faite.
PR #59 a passé la CI sur tous les OS/versions Python — preuve faite.
On retire le patch pour ne pas alourdir l'output pytest avec des
stack traces désormais inutiles.
Le ``pytest_sessionfinish`` existant qui détecte les threads
non-daemon stuck reste actif — toute future fuite continuera d'être
loggée via ``faulthandler.dump_traceback_later(60)``.
https://claude.ai/code/session_011XQZNitg1rCgia8ZD1a2hP
- tests/conftest.py +1 -54
|
@@ -49,49 +49,7 @@ os.environ.pop("PICARONES_PUBLIC_MODE", None)
|
|
| 49 |
os.environ.setdefault("PICARONES_RATE_LIMIT_PER_HOUR", "0")
|
| 50 |
|
| 51 |
|
| 52 |
-
# (3)
|
| 53 |
-
#
|
| 54 |
-
# Stack trace observée systématiquement à la fin de la suite :
|
| 55 |
-
#
|
| 56 |
-
# File "concurrent/futures/process.py", line 587 in _join_executor_internals
|
| 57 |
-
# File "concurrent/futures/process.py", line 106 in _python_exit
|
| 58 |
-
# File "threading.py", line 1594 in _shutdown
|
| 59 |
-
# Error: Process completed with exit code 124.
|
| 60 |
-
#
|
| 61 |
-
# Le ``_python_exit`` de ``concurrent.futures.process`` essaie de joindre des
|
| 62 |
-
# workers de ``ProcessPoolExecutor`` qui n'ont pas été shutdown. Mais nous
|
| 63 |
-
# ne savons pas QUEL test (ou quelle dépendance tierce) instancie ce pool —
|
| 64 |
-
# aucun test du repo n'utilise explicitement ``execution_mode="cpu"``.
|
| 65 |
-
#
|
| 66 |
-
# Ce patch loggue chaque création de ``ProcessPoolExecutor`` avec sa stack
|
| 67 |
-
# trace pour identifier la source. À retirer une fois la cause trouvée.
|
| 68 |
-
import sys as _sys
|
| 69 |
-
import traceback as _traceback
|
| 70 |
-
from concurrent.futures import process as _futures_process
|
| 71 |
-
|
| 72 |
-
_PROCESS_POOL_CREATIONS: list[str] = []
|
| 73 |
-
|
| 74 |
-
|
| 75 |
-
_original_pool_init = _futures_process.ProcessPoolExecutor.__init__
|
| 76 |
-
|
| 77 |
-
|
| 78 |
-
def _logged_pool_init(self, *args, **kwargs): # type: ignore[no-untyped-def]
|
| 79 |
-
stack = _traceback.format_stack()
|
| 80 |
-
record = (
|
| 81 |
-
f"\n[conftest:investigate] ProcessPoolExecutor instancié "
|
| 82 |
-
f"(args={args}, kwargs={kwargs}) — stack :\n"
|
| 83 |
-
+ "".join(stack[-12:]) # 12 derniers frames suffisent pour identifier
|
| 84 |
-
)
|
| 85 |
-
_PROCESS_POOL_CREATIONS.append(record)
|
| 86 |
-
_sys.stderr.write(record)
|
| 87 |
-
_sys.stderr.flush()
|
| 88 |
-
return _original_pool_init(self, *args, **kwargs)
|
| 89 |
-
|
| 90 |
-
|
| 91 |
-
_futures_process.ProcessPoolExecutor.__init__ = _logged_pool_init
|
| 92 |
-
|
| 93 |
-
|
| 94 |
-
# (4) Désactivation préventive du thread daemon de tqdm.
|
| 95 |
# Sur Python 3.12+ (ubuntu-latest en CI), le combo
|
| 96 |
# ``tqdm._monitor`` + ``ProcessPoolExecutor`` (utilisé par
|
| 97 |
# ``picarones.measurements.runner.orchestration`` pour les moteurs
|
|
@@ -156,17 +114,6 @@ def pytest_sessionfinish(session, exitstatus) -> None: # noqa: ARG001
|
|
| 156 |
)
|
| 157 |
sys.stderr.flush()
|
| 158 |
|
| 159 |
-
# Récap des créations de ProcessPoolExecutor capturées par le
|
| 160 |
-
# patch (3) ci-dessus — utile en CI pour voir d'un coup d'œil
|
| 161 |
-
# combien de pools ont été créés et qui est responsable.
|
| 162 |
-
if _PROCESS_POOL_CREATIONS:
|
| 163 |
-
sys.stderr.write(
|
| 164 |
-
f"\n[conftest:investigate] {len(_PROCESS_POOL_CREATIONS)} "
|
| 165 |
-
f"ProcessPoolExecutor créés pendant la session.\n"
|
| 166 |
-
f"Stack traces complètes ci-dessus dans la sortie pytest.\n",
|
| 167 |
-
)
|
| 168 |
-
sys.stderr.flush()
|
| 169 |
-
|
| 170 |
# Si le shutdown hang plus de 60s, on aura les stack traces.
|
| 171 |
faulthandler.dump_traceback_later(
|
| 172 |
timeout=60,
|
|
|
|
| 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
|
|
|
|
| 114 |
)
|
| 115 |
sys.stderr.flush()
|
| 116 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 117 |
# Si le shutdown hang plus de 60s, on aura les stack traces.
|
| 118 |
faulthandler.dump_traceback_later(
|
| 119 |
timeout=60,
|