使用systemd

时间:2016-08-29 05:22:13

标签: python-2.7 raspberry-pi pygame systemd

我正在尝试使用systemd运行python pygame脚本,由于某种原因,脚本只是退出而没有错误。 这是Raspberry Pi与Raspian“Jessie lite”。

如果我使用“sudo python myscript.py”手动运行脚本,它可以正常工作。

sudo systemctl status myscript.service reports:

* myscript.service - Python Script
Loaded: loaded    /etc/systemd/system/myscript.service; enabled)    Active: inactive (dead) since Mon 2016-08-29 04:33:19 UTC; 1s ago
Process: 3275> ExecStart=/usr/bin/python /home/pi/myscript.py (code=killed, signal=HUP)
Main PID: 3275 (code=killed, signal=HUP)

如果我使用sudo systemctl启动myscript.service手动启动服务,则会发生同样的事情。

我已将我的脚本删除到pygame.init()调用。这就是它退出的地方。

如果我尝试手动初始化模块,则“cdrom”,“joystick”,“threads”和“font”正常初始化,但调用display.init()会导致程序退出。没有例外。

我在网上找到的唯一资源是this guy。看来他遇到了我所看到的完全相同的事情。 我试过strace,如果我等了足够长的时间(2分钟),它会起作用! 显然我不能一直用strace跑。我认为它会减慢初始化的执行速度,以某种方式使其工作。

编辑: 所以这个问题似乎是systemd发送一个SIGHUP。如果在Python中未处理此操作,则默认操作是退出。快速解决方法是抓住SIGHUP:

import signal
def handler(signum, frame):
    pass

try:
    signal.signal(signal.SIGHUP, handler)
except AttributeError:
    # Windows compatibility
    pass

这么多灼热的问题。为什么systemd会这样做?为什么strace解决这个问题?为什么有些Python脚本会获得SIGHUP而其他Python脚本却没有?

3 个答案:

答案 0 :(得分:1)

对我来说,解决方案只是初始化我需要的特定模块。

在我的情况下pygame.init()我只初始化pygame.mixer.init(),现在systemd可以启动服务。

答案 1 :(得分:0)

首先,检查您的日志:

journalctl -u myservice.service

将其添加到您的单元文件可能会改善日志记录:

StandardOutput=journal+console

在某些情况下,如果在服务退出之前发生了某些日志记录,则日志不会被服务标记,因此在运行服务之后,还要查看:

journalctl

对于退出服务后的条目。

另外,使用network.target代替network-online.target

我认为应用程序本身可以从命令行运行。假设它以这种方式工作而不是来自systemd,不同的环境变量可能是一个问题。在应用程序顶部添加一行以转储所有环境变量,并在从systemd与CLI运行时比较该输出。

最后,查看Type=的文档。如果默认Type =不适用于您的案例,请相应地进行设置。

systemd可能会更好地回答systemd特有的未来问题,因为它们与编程没有直接关系。

您还应发布<div class="col-md-3"> <div class="btn-group"> <a type="button" class="btn btn-danger btn-justified-90">Proveedor</a> <a type="button" class="btn btn-danger dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"><span class="caret"></span> </a> <ul class="dropdown-menu"> <li><a href="#">Action</a></li> <li><a href="#">Another action</a></li> <li><a href="#">Something else here</a></li> </ul> </div> </div> 单元文件,因为这是您遇到的问题。

答案 2 :(得分:0)

我没有答案,但我遇到了同样的事情,所以我会添加更多细节。

这是减少的代码:

#!/usr/bin/python2.7

import logging
from pygame import display
import signal
import time

def handler(signum, frame):
  """Why is systemd sending sighups? I DON'T KNOW."""
  logging.warning("Got a {} signal. Doing nothing".format(signum))

signal.signal(signal.SIGHUP, handler)
signal.signal(signal.SIGTERM, handler)
signal.signal(signal.SIGCONT, handler)

logging.warning("About to start display.")
try:
  display.init()   # hups
except Exception as ex:
  logging.warning("Got any exception: %s " % ex)

logging.warning("Quitting in 60")
time.sleep(60)

这是产生的日志:

Jul  8 22:30:27 beardog systemd[1]: Started PyGame Test.
Jul  8 22:30:27 beardog pygame[17406]: WARNING:root:About to start display.
Jul  8 22:30:27 beardog pygame[17406]: WARNING:root:Got a 1 signal. Doing nothing
Jul  8 22:30:27 beardog pygame[17406]: WARNING:root:Got a 18 signal. Doing nothing
Jul  8 22:30:27 beardog pygame[17406]: WARNING:root:Quitting in 60

在SIGHUP之后立即获得SIGCONT,但没有SIGTERM。 Systemd声称只在SIGTERM之后发送一个SIGHUP,所以也许它来自其他地方?我在pygame代码中找不到任何相关内容。

我已启用systemd调试日志记录,但它不会打印任何有趣的内容。

这是我的systemd配置。

[Unit]
Description=PyGame Test
After=syslog.target network.target network-online.target graphical.target

[Service]
Type=simple
WorkingDirectory=/path/to/code/pygame/
ExecStart=/path/to/code/pygame/why.py
Restart=always
RestartSec=5
LimitNOFILE=10000
StandardOutput=syslog
StandardError=syslog
SyslogIdentifier=pygame
SendSIGHUP=no

[Install]
WantedBy=multi-user.target

我已经尝试过这样的Type = forking,oneshot和dbus(虽然它不是任何一个)。我也试过TimeoutStartSec = 20,但没有变化。在Ubuntu Xenial笔记本电脑和运行Raspbian的Raspberry pi上测试。 python2.7和python3都有。手动运行时代码工作正常,并且在systemd中的strace下运行时似乎有效。 / O \

和OP一样,我可以通过捕获SIGHUP来解决它,但经过这么多的调试后我很想知道发生了什么。