在程序中使用线程时,Systemd在停止时未收到SIGTERM

时间:2018-08-19 19:00:53

标签: python linux multithreading systemd

我想创建一个作为systemd服务运行的python程序。我希望能够优雅地停止它。我遇到了一个奇怪的行为:当我使用线程时,python程序在systemctl stop example.service上没有收到SIGTERM信号,但是如果我不使用线程,一切都可以正常工作。示例如下:

无线程。 (服务收到SIGTERM信号并按预期停止):

import signal
import time
import threading
import sys

RUN=True

# catch SIGINT and SIGTERM and stop application
def signal_handler(sig, frame):
    global RUN
    print("Got signal: "+str(sig))
    RUN=False
signal.signal(signal.SIGINT, signal_handler)
signal.signal(signal.SIGTERM, signal_handler)

# some working thread inside application
def my_thread():
    global RUN
    while RUN:
        print("sleep")
        time.sleep(1.0)

my_thread()
print("Done.")

stopping a program without threads works

带有线程。 (程序未收到SIGTERM信号,并且在超时后被SIGKILL强制杀死):

import signal
import time
import threading
import sys

RUN=True

# catch SIGINT and SIGTERM and stop application
def signal_handler(sig, frame):
    global RUN
    print("Got signal: "+str(sig))
    RUN=False
signal.signal(signal.SIGINT, signal_handler)
signal.signal(signal.SIGTERM, signal_handler)

# some working thread inside application
def my_thread():
    global RUN
    while RUN:
        print("sleep")
        time.sleep(1.0)

# wait for thread to complete and exit
t = threading.Thread(target=my_thread)
t.start()
t.join()
print("Done.")

stopping a program with threads does not work

系统服务文件:

[Unit]
Description=Example service

[Install]
WantedBy=multi-user.target

[Service]
ExecStart=/usr/bin/python /opt/program/main.py
TimeoutSec=60
Restart=on-failure
Type=simple
User=mixo
Group=mixo

请明确说明:我的程序需要多个线程,因此即使我在程序中使用线程,我也希望能够优雅地停止服务。我在做什么错了?

1 个答案:

答案 0 :(得分:0)

感谢@Shawn提出了这个旧的post,我现在已经解决了这个问题。

问题在于如何在python中实现信号处理程序。 t.join()行阻塞了我的主线程,因此无法接收到任何信号。有两种简单的解决方案:

1)使用python 3.x

或2)使用signal.pause()等待这样的信号:

import signal
import time
import threading
import sys

RUN=True

# catch SIGINT and SIGTERM and stop application
def signal_handler(sig, frame):
    global RUN
    print("Got signal: "+str(sig))
    RUN=False
signal.signal(signal.SIGINT, signal_handler)
signal.signal(signal.SIGTERM, signal_handler)

# some working thread inside application
def my_thread():
    global RUN
    while RUN:
        print("sleep")
        time.sleep(1.0)

# wait for thread to complete and exit
t = threading.Thread(target=my_thread)
t.start()
signal.pause()
t.join()
print("Done.")