Watch at EaseHistorias. Respuestas. Perspectiva.

Tecnología · GUÍA PRÁCTICA

¿Python muestra “BrokenProcessPool”? Identifica el worker muerto antes de reintentar el lote

La excepción del padre solo prueba que un worker terminó mal. Conserva PID y task markers, separa spawn, crash nativo y OOM, y solo entonces reconstruye el pool.

Original technical diagram joining a ProcessPoolExecutor parent task ledger, worker PID markers, and operating-system exit evidence.
Ilustración original: une el Future fallido con el PID del worker y la evidencia de salida. Watch at Ease

BrokenProcessPool significa que al menos un worker de ProcessPoolExecutor terminó de forma no limpia. No demuestra por sí solo una excepción normal, OOM, segfault o error de importación. Al desaparecer un worker, varios Future pendientes pueden recibir la misma excepción del pool.

Une el ledger de tareas del padre, los marcadores PID del worker y la evidencia del sistema operativo. No reenvíes todo el lote hasta aislar una rama causal y un input sospechoso.

Congela el ledger del padre antes de reintentar

Da a cada submission un task ID e input key y registra tiempo, Future y límite de side effects. Al romperse el pool, detén el bulk retry y conserva stderr y service logs.

Varios Future con BrokenProcessPool no prueban que cada input mató un worker.

Marca inicio y fase del worker

En task entry, flush PID, task ID, input key, versión, start method y fase. Mantén el initializer pequeño y determinista y registra entrada y éxito.

Si no aparece el marker, prueba un .py real con main importable, main guard cuando corresponda, callable de nivel de módulo y argumentos serializables. No cambies a fork a ciegas.

Conserva crash nativo y señal

Activa faulthandler antes del código nativo sospechoso y usa stderr duradero. Conserva crash report, estado del servicio, razón del contenedor y exit code disponible.

Un exit status negativo puede ser señal, pero otros workers pueden terminar después de declararse roto el pool. Correlaciona el primer PID muerto.

Demuestra o descarta OOM

En Linux cgroup v2 compara memory.events o memory.events.local antes y después. Un delta de oom_kill prueba una muerte por OOM; high, max y oom significan eventos distintos.

Registra cgroup path, memory.current, memory.peak cuando exista, workers, input size y copias por proceso. Bajar max_workers es experimento, no prueba.

Reduce a un worker y un input

Ejecuta el callable en serie y después en executor de un worker desde archivo real. Mantén task/PID markers y añade inputs por búsqueda binaria.

Si un worker funciona y varios fallan, compara memoria total, file descriptors, native thread pools y start method. Usa un executor nuevo para el experimento.

Cierra con prueba causal

El cierre exige una tarea registrada, un PID conocido, resultado normal o excepción ordinaria, oom_kill sin cambios y ningún crash fatal. Repite con poca concurrencia y cada input una vez.

Solo entonces cambia workers, memory limit, start method, dependencia, initializer o retry policy y documenta causa, versión, ventana e idempotencia.

Original decision diagram separating Python process-pool spawn failures, native crashes, OOM kills, and normal task exceptions.
Ilustración original: cierra una rama causal antes de cambiar concurrencia o reintentos. Watch at Ease