zoukankan      html  css  js  c++  java
  • supervisor stop 进程时,服务的子进程未退出/python 多进程 监听信号 实现所有进程同时退出

    使用 supervisor 管理进程,如果被管理的项目是多进程模式,就需要注意一下:

      1、程序内是否有接收处理 kill -15 signal。

      2、python 程序无法监听 kill -9 信号(其他编程语言没有了解,但按理说应该是一样的),也无法拒绝(kill -9 是立马强制结束进程),所以不要随便使用 kill -9 结束一个进程(kill params[pid], 会允许程序延迟退出,所以程序内可以监听 kill -15 signal),如果使用 kill -9 结束了一个主进程,那么它的子进程就会成为孤儿进程,使用 kill -9 结束某个子进程,就会有可能导致其成为僵尸进程。

      3、如果确实有需要强制结束某个进程,为了安全起见,可以使用 kill  -9  -params[gpid] 代替, 如 kill  -9  -7634,强制立马结束 7634 进程组内的所有进程,正常情况下,主进程的 pid 和该进程组的 gpid 相同,但意义不一样。

      4、kill -15 (默认)和 kill -9 是两种不同的信号,python 程序可以监听 kill -15(也就理所当然的可以拒绝kill -15),但是无法监听 kill -9(也就无法拒绝)

    如果程序没有监听并处理 kill signal 就需要到相应服务的 supervisor 管理配置文件声明:stop 服务时,允许 supervisor stop 该进程组下的所有进程:

    killasgroup=true  # 允许杀死该进程组内的所有进程
    stopasgroup=true  # 允许停止该进程组内的所有进程

    各项信号  值  处理动作  发出信号的原因:

    SIGHUP 1 A 终端挂起或者控制进程终止 
    SIGINT 2 A 键盘中断(如break键被按下:如 control + c) 
    SIGQUIT 3 C 键盘的退出键被按下 
    SIGILL 4 C 非法指令 
    SIGABRT 6 C 由abort(3)发出的退出指令 
    SIGFPE 8 C 浮点异常 
    SIGKILL 9 AEF Kill信号 (无法被程序捕获,程序也无法拒绝)
    SIGSEGV 11 C 无效的内存引用 
    SIGPIPE 13 A 管道破裂: 写一个没有读端口的管道 
    SIGALRM 14 A 由alarm(2)发出的信号 
    SIGTERM 15 A 终止信号 (程序内可以监听该信号,当多进程中的任意进程监听到该信号,就退出所有进程,实现多进程安全退出)
    SIGUSR1 30,10,16 A 用户自定义信号1 
    SIGUSR2 31,12,17 A 用户自定义信号2 
    SIGCHLD 20,17,18 B 子进程结束信号 
    SIGCONT 19,18,25 进程继续(曾被停止的进程) 
    SIGSTOP 17,19,23 DEF 终止进程 
    SIGTSTP 18,20,24 D 控制终端(tty)上按下停止键 
    SIGTTIN 21,21,26 D 后台进程企图从控制终端读 
    SIGTTOU 22,22,27 D 后台进程企图从控制终端写

    python 多进程处理 SIGINT SIGTERM 方式(示例源代码来源于网络,个人增加了注释,以做阐述声明,如有侵权,请联系删除):

    import os
    import sys
    import time
    import signal
    import multiprocessing
    from multiprocessing import Process
    
    
    def fun(x):
        while True:
            print("current pid is % s, group id is % s" % (os.getpid(), os.getpgrp()))
            time.sleep(1)
    
    
    def term(signals, frame):
        print("====current pid is % s, group id is % s"% (os.getpid(), os.getpgrp()))
    
        # os.getpid() 获取当前进程号
        # os.getpgid(params[pid]) 获取当前进程号的所在的组的组进程号
    
        # 杀死某个进程:os.kill(params[pid], params[signal.SIGKILL])
        # 杀死某个进程组下的所有进程:os.killpg(params[gpid], params[signal.SIGKILL])
    
        # os.kill(os.getpid(), signal.SIGKILL)
    
        os.killpg(os.getpgid(os.getpid()), signal.SIGKILL)
    
        print("-------")  # 这行代码永远也不会被执行
    
    
    def signal_handler(signals, frame):
        print('You pressed Ctrl+C,进程号{}'.format(os.getpid()))
        # 优雅地退出(让 control + c 不抛出异常信息)
        sys.exit(0)
    
    
    if __name__ == "__main__":
    
        # 监听信号,注册回调函数(主进程或者子进程都会监听)
        signal.signal(signal.SIGINT, signal_handler)  # control + c 会发送该信号
        signal.signal(signal.SIGTERM, term)
    
        # 程序无法捕获 signal.SIGKIL,会报错(但是可以发送,如 term() 中所示)
        # signal.signal(signal.SIGKILL, term)
    
        processes = list()
        print("currentpid is % s"% os.getpid())
        for i in range(3):
            t = Process(target=fun, args=(str(i),))
            t.daemon = True
            t.start()
            processes.append(t)
    
        try:
            for p in processes:
                p.join()
        except Exception as e:
            print(str(e)

  • 相关阅读:
    C++编程练习(3)----“实现简单的栈的顺序存储结构“
    C++编程练习(2)----“实现简单的线性表的链式存储结构“
    C++编程练习(1)----“实现简单的线性表的顺序存储结构“
    Django--登录实例
    Django--model模型绑定_数据库操作
    Django--初始化
    web框架--MVC、MTV
    CSS--箭头
    CSS--抽屉(dig.chouti.com)页面
    jQuery--加一行减一行
  • 原文地址:https://www.cnblogs.com/lowmanisbusy/p/12733695.html
Copyright © 2011-2022 走看看