Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/281.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python守护进程和systemd服务_Python_Python Daemon_Systemd - Fatal编程技术网

Python守护进程和systemd服务

Python守护进程和systemd服务,python,python-daemon,systemd,Python,Python Daemon,Systemd,我有一个简单的Python脚本作为守护进程工作。我正在尝试创建systemd脚本,以便能够在启动期间启动此脚本 当前systemd脚本: [Unit] Description=Text After=syslog.target [Service] Type=forking User=node Group=node WorkingDirectory=/home/node/Node/ PIDFile=/var/run/zebra.pid ExecStart=/home/node/Node/node.

我有一个简单的Python脚本作为守护进程工作。我正在尝试创建systemd脚本,以便能够在启动期间启动此脚本

当前systemd脚本:

[Unit]
Description=Text
After=syslog.target

[Service]
Type=forking
User=node
Group=node
WorkingDirectory=/home/node/Node/
PIDFile=/var/run/zebra.pid
ExecStart=/home/node/Node/node.py

[Install]
WantedBy=multi-user.target
node.py:

if __name__ == '__main__':
    with daemon.DaemonContext():
        check = Node()
        check.run()
run
包含
而True
循环

我尝试使用
systemctl start zebra node.service
运行此服务。不幸的是,服务从未完成顺序声明-我必须按Ctrl+C。 脚本正在运行,但状态为“正在激活”,一段时间后,它将更改为“正在停用”。 现在我正在使用python守护进程(但在我尝试不使用它之前,症状与之类似)


我应该在脚本中实现一些附加功能,还是systemd文件不正确?

您没有创建PID文件

systemd希望您的程序将其PID写入
/var/run/zebra.PID
。如果您不这样做,systemd可能会认为您的程序失败,因此将其停用

要添加PID文件,请安装并将代码更改为:

import daemon
import daemon.pidlockfile 

pidfile = daemon.pidlockfile.PIDLockFile("/var/run/zebra.pid")
with daemon.DaemonContext(pidfile=pidfile):
    check = Node()
    check.run()
(简要说明:最近更新的
lockfile
更改了其API,使其与python守护程序不兼容。要修复它,请编辑
daemon/pidlockfile.py
,从导入中删除
LinkFileLock
,并将
从lockfile.linklockfile导入linklockfile作为LinkFileLock


请注意另一件事:
DaemonContext
将程序的工作目录更改为
/
,使服务文件的
工作目录
无效。如果希望
DaemonContext
将chdir导入另一个目录,请使用
DaemonContext(pidfile=pidfile,working_directory=“/path/to/dir”)

此外,在创建
DaemonContext()
时,很可能需要设置
daemon_context=True

这是因为,如果
python守护进程
检测到它在init系统下运行,它就不会与父进程分离
systemd
期望运行
Type=forking
的守护进程会这样做。因此,您需要这样做,否则
systemd
将继续等待,并最终终止进程

如果您感到好奇,在
python守护进程
的守护进程模块中,您将看到以下代码:

def is_detach_process_context_required():
    """ Determine whether detaching process context is required.

        Return ``True`` if the process environment indicates the
        process is already detached:

        * Process was started by `init`; or

        * Process was started by `inetd`.

        """
    result = True
    if is_process_started_by_init() or is_process_started_by_superserver():
        result = False

希望这能更好地解释。

可以像Schnouki和Amit描述的那样进行daemonize。但对于systemd来说,这是不必要的。初始化守护进程有两种更好的方法:套接字激活和使用sd_notify()显式通知

套接字激活适用于希望在网络端口或UNIX套接字或类似端口上侦听的守护进程。Systemd将打开套接字,监听它,然后在连接进入时生成守护进程。这是首选方法,因为它为管理员提供了最大的灵活性。[1] [2]给出了一个很好的介绍,[3]描述了C API,而[4]描述了Python API

[1]
[2]
[3]
[4]

显式通知意味着守护进程打开套接字本身和/或执行任何其他初始化,然后通知init它已经准备好并可以为请求提供服务。这可以通过“forking协议”实现,但实际上,使用sd_notify()向systemd发送通知更好。 Python包装器名为systemd.daemon.notify,将作为一行使用[5]

[5]

在这种情况下,单位文件的Type=notify,并调用
systemd.daemon.notify(“READY=1”)在建立套接字之后。无需分叉或后台处理。

其原因是,对于类型
分叉
而言,您的启动过程将分叉并退出(请参阅$man systemd.service-搜索分叉)

只需使用主进程,不进行后台监控 一个选择是做得更少。使用systemd,通常不需要创建守护进程,您可以直接运行代码而无需守护进程

#!/usr/bin/python -u
from somewhere import Node
check = Node()
check.run()
这允许使用名为
simple
的更简单的服务类型,因此您的单位文件看起来像

[Unit]
Description=Simplified simple zebra service
After=syslog.target

[Service]
Type=simple
User=node
Group=node
WorkingDirectory=/home/node/Node/
ExecStart=/home/node/Node/node.py
StandardOutput=syslog
StandardError=syslog

[Install]
WantedBy=multi-user.target
请注意,python shebang中的
-u
是不必要的,但如果您将某些内容打印到标准输出或标准输出,则
-u
确保没有适当的输出缓冲,并且打印的行将立即被systemd捕获并记录在日志中。如果没有它,它会出现一些延迟

为此,我在单元文件中添加了行
StandardOutput=syslog
StandardError=syslog
。如果您不关心日记中的打印输出,请不要关心这些行(它们不必存在)

systemd
使daemonization过时 虽然您问题的标题明确询问了守护进程,但我想,问题的核心是“如何使我的服务运行”,虽然使用主进程似乎简单得多(您根本不必关心守护进程),但它可以被视为您问题的答案

我认为,很多人使用Daemoning只是因为“每个人都这么做”。使用systemd时,后台监控的原因通常是过时的。使用守护进程可能有一些原因,但现在这种情况很少见


编辑:将
python-p
修改为正确的
python-u
。感谢kmftzg

我在CentOS 7下尝试将一些python init.d服务转换为systemd时遇到了这个问题。通过将此文件放置在
/etc/systemd/system/
中,这似乎对我来说非常有用:

[Unit]
Description=manages worker instances as a service
After=multi-user.target

[Service]
Type=idle
User=node
ExecStart=/usr/bin/python /path/to/your/module.py
Restart=always
TimeoutStartSec=10
RestartSec=10

[Install]
WantedBy=multi-user.target
然后,我从
/etc/init.d
中删除了旧的init.d服务文件,并运行
sudo systemctl daemon reload
来重新加载systemd

我希望我的服务能够自动重启,因此需要重启选项。我还发现使用
idle
进行
Type
比使用
simple
更有意义

空闲行为与简单行为非常相似;然而,实际执行 服务二进制文件的调度将延迟,直到调度所有活动作业。 这可用于避免交错
[Unit]
# Added this to the above
#SourcePath=/etc/init.d/old-service 

[Service]
# Replace the ExecStart from above with these
#ExecStart=/etc/init.d/old-service start
#ExecStop=/etc/init.d/old-service stop