如何使 Python 脚本作为服务运行?

Posted

技术标签:

【中文标题】如何使 Python 脚本作为服务运行?【英文标题】:How to make Python script run as service? 【发布时间】:2013-05-01 11:14:37 【问题描述】:

我想在 CENTOS 服务器上运行一个 python 脚本:

#!/usr/bin/env python
import socket
try:    
    import thread 
except ImportError:
    import _thread as thread #Py3K changed it.
class Polserv(object):
    def __init__(self):
        self.numthreads = 0
        self.tidcount   = 0
        self.port       = 843
        self.sock       = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        self.sock.bind(('100.100.100.100', self.port))
        self.sock.listen(5)
    def run(self):
        while True:
            thread.start_new_thread(self.handle, self.sock.accept()) 
    def handle(self,conn,addr):
        self.numthreads += 1
        self.tidcount   += 1
        tid=self.tidcount
        while True:
            data=conn.recv(2048)
            if not data:
                conn.close()
                self.numthreads-=1
                break
            #if "<policy-file-request/>\0" in data:
            conn.sendall(b"<?xml version='1.0'?><cross-domain-policy><allow-access-from domain='*' to-ports='*'/></cross-domain-policy>")
            conn.close()
            self.numthreads-=1
            break
        #conn.sendall(b"[#%d (%d running)] %s" % (tid,self.numthreads,data) )
Polserv().run()

我正在使用$ python flashpolicyd.py,它工作正常... 问题是:即使在我关闭终端(控制台)后,如何保持此脚本运行?

【问题讨论】:

How to make a python script run like a service or daemon in linux 的可能重复项 不是完全重复的——链接到的问题是关于一个重复性任务,这是关于一个网络守护进程;另一个的解决方案是 cron,解决方案是 inetd(或等效)。 【参考方案1】:

我使用this 代码来守护我的应用程序。它允许您使用以下命令start/stop/restart 脚本。

python myscript.py start
python myscript.py stop
python myscript.py restart

除此之外,我还有一个init.d 脚本来控制我的服务。这允许您在操作系统启动时自动启动服务。

这里有一个简单的例子来帮助你。只需将您的代码移动到一个类中,然后从MyDeamon 中的run 函数调用它。

import sys
import time

from daemon import Daemon


class YourCode(object):
    def run(self):
        while True:
            time.sleep(1)


class MyDaemon(Daemon):
    def run(self):
        # Or simply merge your code with MyDaemon.
        your_code = YourCode()
        your_code.run()


if __name__ == "__main__":
    daemon = MyDaemon('/tmp/daemon-example.pid')
    if len(sys.argv) == 2:
        if 'start' == sys.argv[1]:
            daemon.start()
        elif 'stop' == sys.argv[1]:
            daemon.stop()
        elif 'restart' == sys.argv[1]:
            daemon.restart()
        else:
            print "Unknown command"
            sys.exit(2)
        sys.exit(0)
    else:
        print "usage: %s start|stop|restart" % sys.argv[0]
        sys.exit(2)

新贵

如果您正在运行使用 Upstart 的操作系统(例如 CentOS 6) - 您也可以使用 Upstart 来管理服务。如果您使用 Upstart,您可以保持脚本不变,只需在 /etc/init/my-service.conf 下添加类似这样的内容@

start on started sshd
stop on runlevel [!2345]

exec /usr/bin/python /opt/my_service.py
respawn

然后您可以使用启动/停止/重新启动来管理您的服务。

例如

start my-service
stop my-service
restart my-service

here 提供了与 upstart 合作的更详细示例。

系统化

如果您正在运行使用 Systemd 的操作系统(例如 CentOS 7),您可以查看以下*** answer。

【讨论】:

好的..但我看不到如何在我的脚本中使用这个类...你可以教吗? 您将如何将 init.d 脚本与 MyDaemon 一起使用?假设 Daemon 分叉 MyDaemon 进程可能会分叉一个新进程,然后它可能会尝试重新启动 - 因为它认为脚本已经完成(导致 1000 个正在运行的 python 进程)。你能用简单的python Dameon提供一个快速/简单的init.d示例吗? @sigi:除非脚本实际完成,否则 python 守护进程应该会阻止任何新进程启动,但您始终可以只检查 init.d 脚本中的 pid 文件。如果您需要适当的示例,我可以在一两天内有时间更新答案。 @eandersson:我认为您提到的 python 守护程序脚本会执行两次进程分叉,因此我认为 init.d (Upstart) 需要在“.conf”中有一个“期望守护程序”命令" 文件或类似的东西......我只是想知道你如何让你的 Upstart .conf 文件使用你引用的守护进程脚本来寻找一个简单的 python 守护进程 - 即一个你如何使用 init.d 的简单示例用于控制您的服务的脚本真的很棒......谢谢。 @MohitC:不幸的是,这有点离题了。我建议您专门针对妖魔化多进程应用程序打开一个新问题。【参考方案2】:

我提出两个建议:

主管

1) 安装supervisor 包(more verbose instructions here):

sudo apt-get install supervisor

2) 在/etc/supervisor/conf.d/flashpolicyd.conf 为您的守护程序创建一个配置文件:

[program:flashpolicyd]
directory=/path/to/project/root
environment=ENV_VARIABLE=example,OTHER_ENV_VARIABLE=example2
command=python flashpolicyd.py
autostart=true
autorestart=true

3) 重启supervisor 以加载新的.conf

supervisorctl update
supervisorctl restart flashpolicyd

systemd(如果您的 Linux 发行版当前使用)

[Unit]
Description=My Python daemon

[Service]
Type=simple
ExecStart=/usr/bin/python3 /opt/project/main.py
WorkingDirectory=/opt/project/
Environment=API_KEY=123456789
Environment=API_PASS=password
Restart=always
RestartSec=2

[Install]
WantedBy=sysinit.target

将此文件放入/etc/systemd/system/my_daemon.service 并使用systemctl daemon-reload &amp;&amp; systemctl enable my_daemon &amp;&amp; systemctl start my_daemon --no-block 启用它。

查看日志:

systemctl status my_daemon

【讨论】:

超级简单的方法:) 嗨@Freude!我在答案中添加了 systemd 守护进程配置。现在许多 Linux 都附带 systemd 用于 init 脚本,并且配置与 supervisord 非常相似。 .service文件应该在CentOS的/lib/systemd/system/下创建 是否可以在execstart上写相对路径? 使用这个 systemd 方法我可以让守护进程正常工作,但它在重启后无法启动,并出现以下错误:Job active_controller.service/start deleted to break ordering cycle started with sysinit.target/start跨度> 【参考方案3】:

我的非 pythonic 方法是使用 & 后缀。那就是:

python flashpolicyd.py &

停止脚本

killall flashpolicyd.py

带有 disown 的管道和后缀也会将该进程置于父级(上)之下:

python flashpolicyd.pi & disown

【讨论】:

最后一个不工作(Ubuntu 16.04):-bash: syntax error near unexpected token '|'【参考方案4】:

首先在您的应用程序中导入 os 模块,而不是使用 getpid 函数获取 pid 的应用程序并保存在文件中。例如:

import os
pid = os.getpid()
op = open("/var/us.pid","w")
op.write("%s" % pid)
op.close()

并在 /etc/init.d 路径中创建一个 bash 文件: /etc/init.d/服务器名

PATHAPP="/etc/bin/userscript.py &"
PIDAPP="/var/us.pid"
case $1 in 
        start)
                echo "starting"
                $(python $PATHAPP)
        ;;
        stop)
                echo "stoping"
                PID=$(cat $PIDAPP)
                kill $PID
        ;;

esac

现在,您可以使用 down 命令启动和停止您的应用程序:

服务服务器名停止 服务服务器名开始

/etc/init.d/servername 停止 /etc/init.d/servername 启动

【讨论】:

【参考方案5】:

对于我的 python 脚本,我使用...

启动 python 脚本:

start-stop-daemon --start --background --pidfile $PIDFILE --make-pidfile --exec $DAEMON

停止 python 脚本:

PID=$(cat $PIDFILE)
kill -9 $PID
rm -f $PIDFILE

P.S.:抱歉英语不好,我来自智利 :D

【讨论】:

以上是关于如何使 Python 脚本作为服务运行?的主要内容,如果未能解决你的问题,请参考以下文章

如何使 Python 脚本像 Linux 中的服务或守护程序一样运行

如何让 python 脚本作为可执行文件运行? [复制]

如何在 Windows 中将 Python 脚本作为服务运行?

如何将多个图像作为输入传递给python脚本

如何确定 Python 脚本作为哪个用户和组运行?

如何休眠作为 cronjob 运行的 python 脚本?