Как настроить демон для уничтожения других процессов в его группе процессов, когда он умирает - PullRequest
1 голос
/ 03 апреля 2019

Я хочу создать демон Manager, который порождает два подпроцесса A и B. Когда демон Manager умирает / убивается, он должен убить A и B. В настоящее время он настроен так, что если я передам "stop" в Manager, он отправит SIGTERM в свою группу процессов, которая убивает все.

Однако мне бы хотелось, чтобы, если я отправлю SIGTERM на Manager напрямую, это также убило бы A и B. Я пробовал обработчики сигналов, но это создает цикл, в котором он отправляет SIGTERM на PG, который отправляет его обратно на Manager и т. Д.

Я также пытался сделать Manager лидером группы процессов, вызвав os.setpgid(os.getpid(), os.getpid()) до появления A и B, но это, похоже, не убивает A и B должным образом.

В приведенном ниже примере выполнение python manager.py start приведет к созданию Manager, A и B. Тогда:

  1. python manager.py stop уничтожит все 3 процесса
  2. kill -INT -$MANAGER_PGID убьет всех 3
  3. kill $MANAGER_PID убьет только Manager, а не A или B
#!/usr/bin/env python2.7

import atexit
import datetime
import os
import sys
import time
import subprocess
from signal import *


class Daemon(object):
    def __init__(self):
        self.pid_file = "/var/run/manager.pid"

    def del_pid(self):
        os.remove(self.pid_file)

    def daemonize(self):
        if os.fork():
            sys.exit()
        os.chdir("/")
        os.setsid()
        os.umask(0)
        if os.fork():
            sys.exit()
        with open('/dev/null', 'r') as dev_null:
            os.dup2(dev_null.fileno(), sys.stdin.fileno())

        sys.stderr.flush()
        err = "/tmp/manager.err"
        with open(err, 'a+', 0) as stderr:
            os.dup2(stderr.fileno(), sys.stderr.fileno())

        sys.stdout.flush()
        out = "/tmp/manager.out"
        with open(out, 'a+', 0) as stdout:
            os.dup2(stdout.fileno(), sys.stdout.fileno())

        atexit.register(self.del_pid)
        pid = os.getpid()
        with open(self.pid_file, 'w+') as pid_file:
            pid_file.write('{0}'.format(pid))
        os.setpgid(pid, pid)
        # for sig in (SIGABRT, SIGTERM, SIGINT):
        #     signal(sig, self.stop)

    def get_pid_by_file(self):
        with open(self.pid_file, 'r') as pid_file:
           pid = int(pid_file.read().strip())
        return pid

    def start(self):
        self.daemonize()
        self.run()

    def stop(self, signum=None, frame=None):
        pid = self.get_pid_by_file()
        pgid = os.getpgid(pid)
        os.killpg(pgid, SIGTERM)

    def run(self):
        subprocess.Popen("a.sh", shell=True)
        subprocess.Popen("a.sh", shell=True)
        while 1:
            time.sleep(5)

if __name__ == '__main__':
    daemon = Daemon()
    if 'start' == sys.argv[1]:
        daemon.start()
    elif 'stop' == sys.argv[1]:
        daemon.stop()

1 Ответ

0 голосов
/ 03 апреля 2019

Поскольку я создаю и использую файл PID для поиска процессов, которые нужно остановить, я остановил цикл, установив проверку, существует ли файл PID или нет.

...