Tengo un módulo que uso para situaciones como esta, donde un proceso se ejecutará durante mucho tiempo pero a veces se atasca por razones desconocidas e irreproducibles. Es un poco hacky, y solo funciona en Unix (requiere señales):
import code, traceback, signal
def debug(sig, frame):
"""Interrupt running process, and provide a python prompt for
interactive debugging."""
d={'_frame':frame} # Allow access to frame object.
d.update(frame.f_globals) # Unless shadowed by global
d.update(frame.f_locals)
i = code.InteractiveConsole(d)
message = "Signal received : entering python shell.\nTraceback:\n"
message += ''.join(traceback.format_stack(frame))
i.interact(message)
def listen():
signal.signal(signal.SIGUSR1, debug) # Register handler
Para usar, simplemente llame a la función listen () en algún momento cuando su programa se inicie (incluso podría pegarlo en site.py para que todos los programas de Python lo usen) y dejarlo correr. En cualquier momento, envíe al proceso una señal SIGUSR1, usando kill o en python:
os.kill(pid, signal.SIGUSR1)
Esto hará que el programa se rompa a una consola de Python en el punto en el que se encuentra actualmente, mostrándole el seguimiento de la pila y permitiéndole manipular las variables. Use control-d (EOF) para continuar ejecutándose (aunque tenga en cuenta que probablemente interrumpirá cualquier E / S, etc. en el punto que indique, por lo que no es totalmente no intrusivo).
Tengo otro script que hace lo mismo, excepto que se comunica con el proceso en ejecución a través de una tubería (para permitir la depuración de procesos en segundo plano, etc.). Es un poco grande para publicar aquí, pero lo he agregado como una receta de libro de cocina de Python .