【问题标题】:Systemd not receiving SIGTERM on stop when using threads in program在程序中使用线程时,Systemd 在停止时未收到 SIGTERM
【发布时间】:2019-01-26 00:04:19
【问题描述】:

我想创建一个作为 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.")

带螺纹。 (程序没有收到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.")

Systemd 服务文件:

[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

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

【问题讨论】:

标签: python linux multithreading systemd


【解决方案1】:

感谢@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.")

【讨论】:

    猜你喜欢
    • 2016-07-01
    • 2012-05-07
    • 2010-10-07
    • 2020-02-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多