Tecnología · GUÍA PRÁCTICA
¿queue.join() de Python se queda colgado? Audita tareas pendientes y workers
Separa el contenedor vacío del contador de tareas, detecta consumidores muertos, cuenta centinelas y elige el cierre sin fingir que el trabajo terminó.

queue.join() no espera a que el contenedor parezca vacío, sino a que el contador de tareas pendientes llegue a cero. put lo incrementa y task_done lo reduce. Si un worker retira el último elemento y muere, se cancela o sale antes de confirmarlo, empty() puede ser verdadero mientras join espera.
Empareja cada get correcto con un solo task_done en finally y observa los workers junto con join. Los centinelas también cuentan. En Python 3.13+, el cierre inmediato puede liberar join sin ejecutar el trabajo, por lo que debe registrarse como abandono.
1. Demuestra qué contador está bloqueado
Registra put, get y task_done con ID, worker y tiempo monotónico; reconcilia inserciones menos confirmaciones. empty solo describe el contenedor.
No borres la estructura interna ni modifiques unfinished_tasks: puedes crear una finalización falsa.
2. Confirma una vez incluso con excepciones
Tras un get correcto, usa try/finally y llama a task_done en finally. No confirmes si get no devolvió un elemento.
Registra el éxito de negocio aparte y evita una segunda confirmación que causaría ValueError.
3. Observa workers y join
En asyncio espera join y workers a la vez; si un worker termina primero, propaga su excepción.
En hilos conserva referencias y señal de parada. Un timeout diagnostica, no completa.
4. Cuenta centinelas y elige shutdown
Un centinela sigue siendo un elemento encolado y debe confirmarse antes de salir.
shutdown(False) conserva la garantía; shutdown(True) solo sirve para abandono explícito y debe informar lo descartado.
5. Prueba cronologías de fallo
Prueba drenaje, excepción, cancelación, centinela perdido, salida temprana y ambos cierres.
Exige estado terminal por trabajo, ningún put tardío, workers detenidos y abandonos no marcados como éxito.
