done_callback raises RuntimeError during interpreter shutdown
Nadie ha tomado este issue todavía.
Evaluación
- Dificultad
- 2/5
- Tiempo estimado
- 1-3 horas
- Aptitud para principiantes
- 50/100
- Tipo de issue
- Error
- Claridad
- Bien especificado
- Estado de actividad
- Estancado
- Stack tecnológico
- python
- Área
- distributed-systems
Línea de trabajo
Empieza en client.py, en done_callback, y sigue la ruta callback(future) hasta _cb_executor.submit(execute_callback). Ejecuta el ejemplo mínimo completo y verificable durante el apagado del intérprete; done significa que se ignora el RuntimeError relacionado con el apagado, mientras que los demás casos de RuntimeError siguen manifestándose.
Escrito por el modelo de indexación a partir del texto del issue.
Descripción
Describe the issue:
done_callback in client.py raises RuntimeError: cannot schedule new futures after interpreter shutdown when futures complete during interpreter shutdown.
Future.add_done_callback() schedules callbacks via Future._cb_executor (a class-level ThreadPoolExecutor). During shutdown, CPython's concurrent.futures.thread._python_exit() atexit handler kills all ThreadPoolExecutor instances and sets a module-level _shutdown = True flag. The Tornado IOLoop daemon thread is still alive draining done_callback coroutines — when they call _cb_executor.submit(), it raises RuntimeError.
The fix is to catch shutdown-related RuntimeError in done_callback since the callback is no longer meaningful if the interpreter is shutting down.
Minimal Complete Verifiable Example:
import time
from distributed import Client, LocalCluster
def on_done(future):
print(f"Callback: {future.key}")
if __name__ == "__main__":
cluster = LocalCluster(n_workers=2, threads_per_worker=1)
client = Client(cluster)
# pure=False ensures unique keys; staggered sleeps so futures complete during shutdown
futures = client.map(time.sleep, [0.2 * i for i in range(20)], pure=False)
for f in futures:
f.add_done_callback(on_done)
# Exit while futures are still completing — don't call client.close()
time.sleep(1.5)
Anything else we need to know?:
The error path is: done_callback → callback(future) → _cb_executor.submit(execute_callback) → RuntimeError.
Even creating a new ThreadPoolExecutor would not help because CPython's concurrent.futures.thread.submit() checks both the instance flag (self._shutdown) and the module-level flag (_shutdown), which was already set by _python_exit().
Suggested fix in done_callback:
async def done_callback(future, callback):
while future.status == "pending":
await future._state.wait()
try:
callback(future)
except RuntimeError as e:
if "shutdown" not in str(e) and "interpreter" not in str(e):
raise
This is also a prerequisite for a related dask-gateway bug where cleanup_lingering_clusters atexit fails to send HTTP DELETE to shut down clusters because the same executor shutdown blocks aiohttp's DNS resolution.
Environment:
- Dask version: 2025.9.1
- Python version: 3.11.14
- Operating System: macOS 15.7.4 (arm64)
- Install method: uv (pip)
- Lenguaje dominante
- Python
- Estrellas
- 1.7k
- Forks
- 778
- Métricas de merge de PR
- Sin PR fusionados en 30 d
Preparar el entorno
Primeros pasos
- Lee el issue completo y luego la guía de contribución del proyecto.
- Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
- Haz un fork del repositorio y trabaja en una rama.
- Abre un pull request que haga referencia al número del issue.
Más de dask/distributed
-
needs triage
Dificultad 2/5 1-3 horas Aptitud para principiantes 72/100
dask/distributed#9366 ·
-
needs triage
Dificultad 2/5 1-3 horas Aptitud para principiantes 84/100
dask/distributed#9353 ·
-
documentation
Dificultad 1/5 1-3 horas Aptitud para principiantes 82/100
dask/distributed#8304 ·
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 74/100
dask/distributed#4816 · 2 comentarios ·
-
documentation good first issue
Dificultad 2/5 1-3 horas Aptitud para principiantes 74/100
dask/distributed#2378 · 2 comentarios ·
Todos los issues de dask/distributed
Issues similares
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 72/100
-
bug
Dificultad 1/5 Menos de una hora Aptitud para principiantes 88/100
qgis/QGIS-Plugins-Website#459 ·
-
bug severity:medium
Dificultad 2/5 1-3 horas Aptitud para principiantes 78/100
Los mantenedores suelen responder en 2 días
-
bot-found bug priority: P3
Dificultad 2/5 1-3 horas Aptitud para principiantes 84/100
madenvel/KalinkaPlayer#179 ·
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 68/100
ls1intum/edutelligence#1098 ·
Los mantenedores suelen responder en 1 día