Sam Hooke

Debugging a Python process not terminating due to active threads

Situation §

A multi-threaded Python process is not terminating because a non-daemon thread is still alive. Given a running Python process, we want to identify the name of this thread.

Resolution §

Identify the PID of the Python process:

(virtualenv) [user@hostname ~]$ ps aux | grep python
root       859  0.0  0.4 553080  2288 ?        Ssl  Apr26   1:59 /usr/bin/python -Es /usr/sbin/tuned -l -P
appuser  14738  0.2  2.9 825472 14868 ?        Sl   10:11   0:02 /opt/myapp/virtualenv/bin/python -m myapp_package

Connect Pyrasite to the Python process:

(virtualenv) [user@hostname ~]$ pyrasite-shell 14738
Pyrasite Shell 2.0
Connected to '/opt/myapp/virtualenv/bin/python -m myapp_package'
Python 2.7.5 (default, Nov  6 2016, 00:28:07)
[GCC 4.8.5 20150623 (Red Hat 4.8.5-11)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
(DistantInteractiveConsole)

>>> 

Use REPL to identify extrenuous threads:

>>> import threading
>>> threading.active_count()
3

>>> threading.current_thread()
<ReversePythonShell(Thread-4, started 140499363800832)>

>>> threading.enumerate()
[<_MainThread(MainThread, stopped 140499644737344)>, <ReversePythonShell(Thread-4, started 140499363800832)>, <NaughtyThread(Thread-2, started 140498966664960)>]
>>>

In the above we identify that there are three threads: _MainThread, which is the main thread and has stopped; ReversePythonShell, which is the thread Pyrasite is running in and so is still active; and NaughtyThread, which by process of elimination is the extrenuous thread which is keeping the process alive. The name corresponds to the name of the Python class.