Завершение подпроцесса в Python - PullRequest
2 голосов
/ 29 декабря 2010

Полностью переписано на основе моего собственного расследования

У меня есть мастер-скрипт, который запускает ряд других скриптов на Python. Сценарии создаются как

from subprocess import STDOUT, Popen
from signal import SIGINT
import shlex
p = Popen(shlex.split("python somescript.py arg1 arg2"), cwd="../src/somedir", stderr=STDOUT)

И заканчиваются

p.send_signal(SIGINT)
p.wait()

Внутри них есть следующий код

if __name__ == "__main__":

    import signal
    def terminate(*args):
        raise KeyboardInterrupt
    signal.signal(signal.SIGINT, terminate)

    # do some work here

Каждый скрипт имеет некоторую функцию, имеющую

try:
    # create workers
except KeyboardInterrupt:
    # cleanup, wait for the current worker to end, then return

Все описанные работы работают так, как предполагалось - мастер-сценарий создает процессы, когда его выполнение заканчивается, он отправляет им SIGINT, они обрабатывают его правильным образом, изящно завершая работу.

Теперь я хочу запустить сервер разработки Django таким же образом.

Я изменил файл manage.py:

if __name__ == "__main__":
    import signal
    def terminate(*args):
        print 'got SIGINT'
        raise KeyboardInterrupt
    signal.signal(signal.SIGINT, terminate)

    execute_manager(settings)

Функция execute_manager после нескольких вызовов приводит к методу команды django, имеющему блок except KeyboardInterrupt с sys.exit(0). Итак, вся установка выглядит одинаково.

Проблема: сервер django фактически не останавливается, хотя я вижу вывод got SIGINT.

Возможно объяснение:

Похоже, django manage.py разветвляется или делает что-то подобное; заглядывая в Activity Monitor (обозреватель процессов osx), я вижу 3 запущенных процесса на python - один для главного сценария и, возможно, 2 для manage.py. При завершении 2 из них останавливаются (основной сценарий и тот, на который у меня есть ссылка с p), в то время как третий продолжает блокировать порт 8000. Есть ли способ получить pids подпроцесса процесса?

1 Ответ

0 голосов
/ 30 декабря 2010

Вы можете использовать psutil , чтобы узнать о дочерних процессах, например, в псевдокоде:

p = Popen(...)
pp = psutil.Process(p.pid)
for child in pp.get_children():
    child.send_signal(signal.SIGINT)

Обратите внимание на разницу в процессах при запуске без --reload, полученную с помощью ps -ef | grep manage.py | grep -v grep:

vinay 7864 7795  9 22:10 pts/0 00:00:00 python ./manage.py runserver
vinay 7865 7864 16 22:10 pts/0 00:00:00 /usr/bin/python ./manage.py runserver

по сравнению с опцией --noreload:

vinay 7874 7795  7 22:10 pts/0 00:00:00 python ./manage.py runserver --noreload
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...