Python SIGINT SIGTERM不会立即退出while循环

时间:2018-07-13 14:29:41

标签: python sigint sigterm

def do_stuff_before_python_terminates():
    save_variables_in_mysql()
    do_this_and_that()...

def main():
    do stuff
    while loops ect...

def sigterm(x, y):
    raise Exception()
def sigint(signal, frame):
    raise Exception()





signal.signal(signal.SIGINT, sigint)
signal.signal(signal.SIGTERM, sigterm)  
try:
    while True:
        main()
except Exception as e:
    logger.error("Exception")
    do_stuff_before_python_terminates()
    logger.log("sys.exit")
    sys.exit(0)

我在Docker容器中使用Python

当我通过tty终端执行ctrl + c或停止图像时 python确实会停止并且并非总是成功 “ do_stuff_before_python_terminates()”。

原因是,当python随机地处于while循环中时,我没有运气,它不会退出,它会停留在while循环中,并且还会进行其他处理,并且不会成功终止。

Docker杀死容器仅等待10秒钟,比起voila,它不会“ do_stuff_before_python_terminates()”

我在这里做什么错了,如何解决即使在它的while循环中它立即退出并出现“ do_stuff_before_python_terminates()”的问题

更新说明:

如果python抛出错误

它确实成功跳转到

except Exception as e:
    logger.error("Exception")
    do_stuff_before_python_terminates()
    logger.log("sys.exit")
    sys.exit(0)

如果我停止容器或使用ctrl + c并且python不在while循环中

它确实成功跳转到

sigterm() or sigint() -> then raise an Exception() ->  then jumps to
except Exception as e:
    logger.error("Exception")
    do_stuff_before_python_terminates()
    logger.log("sys.exit")
    sys.exit(0)

如果我停止容器或使用ctrl + c并且python处于循环中

it does stay in the loop 
do stuff
do stuff
do stuff
after nearly 20-30seconds
sigterm() or sigint() -> then raise an Exception() ->  then jumps to
except Exception as e:
    logger.error("Exception")
    do_stuff_before_python_terminates()
    logger.log("sys.exit")
    sys.exit(0)

我需要的是,每当我停止容器或执行ctrl + c(sigterm + sigint)时,它确实会立即跳出while循环

sigterm() or sigint() -> then raise an Exception() ->  then jumps to
except Exception as e:
    logger.error("Exception")
    do_stuff_before_python_terminates()
    logger.log("sys.exit")
    sys.exit(0)

Docker会在10秒后杀死容器,因此python仅退出10秒,结果是当python处于循环中时,它从不执行do_stuff_before_python_terminates()

3 个答案:

答案 0 :(得分:0)

您的do_stuff_before_python_terminates()调用不正确(至少从我对信号和python的经验来看)。

do_stuff_before_python_terminates()和/或sigterm函数中调用sigint

def do_stuff_before_python_terminates():
    save_variables_in_mysql()
    do_this_and_that()...

def sigterm(x, y):
    do_stuff_before_python_terminates()
    raise Exception()
def sigint(signal, frame):
    do_stuff_before_python_terminates()
    raise Exception()

请确保将do_stuff函数放在sigterm和sigint函数上方。

答案 1 :(得分:0)

  1. 在main()中注册信号。例如:

        def signal_handler(signal, frame):
                print('\n')
                sys.exit(0)
    
        def main():
            signal.signal(signal.SIGINT, signal_handler)
            do_stuff_before_python_terminates()
    
  2. 直到底层C代码完成,信号才会触发。来自文档:“纯粹用C实现的长时间运行的计算(例如,在大文本正文上进行正则表达式匹配)可能会在任意时间内无中断运行,而不管收到任何信号。Python信号处理程序将被调用计算完成后。”

答案 2 :(得分:0)

来自Execution of Python signal handlers

  

纯粹用C语言实现的长时间运行的计算(例如,在大文本正文上进行正则表达式匹配)可以在任意时间内连续运行,而不管收到任何信号。计算完成后,将调用Python信号处理程序。

这可能是导致您出现问题的原因。由于此限制(and others),用Python编写的信号处理程序除了在最简单的程序中外,很少表现出预期的作用。

如果您确实确实需要立即捕获信号,则可能需要使用调用Python代码的低级语言(例如C)为程序编写包装。