2009-01-23 31 views
210

Searching on Google显示x2代码片段。第一个结果是this code recipe,它有很多文档和解释,以及下面的一些有用的讨论。你如何在Python中创建一个守护进程?

但是,another code sample虽然没有包含太多文档,但包含用于传递诸如启动,停止和重新启动之类的命令的示例代码。它还会创建一个PID文件,用于检查守护进程是否已在运行等。

这些示例都解释了如何创建守护进程。还有什么需要考虑的吗?一种样品比另一种好,为什么?

+1

我总是发现系统守护进程的代码不必要的。为什么不让壳体做到这一点? – 2010-11-13 20:12:22

+14

因为它不会执行setsid或setpgrp。 – bmargulies 2011-03-24 01:26:56

+4

使用http://supervisord.org/。这样你就不需要fork()或重定向你stdin/stderr。只需编写一个正常的程序。 – guettli 2013-10-01 09:02:22

回答

131

Sander Marechal的code sample优于最初于2004年发布的原始版本。我曾经贡献过Pyro的一个守护进程,但如果必须完成它,可能会使用Sander的代码。

+70

编辑:因为我最初发布这个答复,PEP 3143的参考实现在现已:http://pypi.python.org/pypi/python-daemon/ – 2011-01-28 18:45:05

+3

蟒蛇守护封装使这项任务更容易... – Pankaj 2011-04-17 09:16:03

+0

@JeffBauer原始链接已经死亡,我记得它很有用,你不会知道一个活的链接,你会吗? – CrazyCasta 2014-02-25 19:43:24

-24

80%的时间,当人们说“守护进程”时,他们只想要一台服务器。由于这个问题在这方面完全不清楚,很难说可能的答案领域是什么。由于服务器足够,从那里开始。如果实际需要一个实际的“守护进程”(这很少见),请阅读nohup作为守护进程服务器的一种方式。

在真正需要实际守护进程的时候,只需编写一个简单的服务器即可。

另请参阅WSGI reference实现。

也看看Simple HTTP Server

“还有什么需要考虑的事情吗?”是的。大约一百万件事。什么协议?有多少请求?每个请求需要多长时间?他们多久会抵达?你会使用专门的过程吗?主题?子进程?编写一个守护进程是一项很重要的工作。

-2

使用Python创建守护程序的最简单方法是使用Twisted事件驱动框架。它为你处理守护进程所需的所有东西。它使用Reactor Pattern来处理并发请求。

146

很多繁琐的事情照顾成为well-behaved daemon process时:

  • 防止核心转储(许多守护进程以root身份运行,并且核心转储可能包含敏感信息)

  • 内部正确运作chroot gaol

  • 设置UID,GID,工作目录,umask和其他过程参数LY的使用情况

  • 才肯罢休升高suidsgid特权

  • 关闭所有打开的文件描述符,以根据不同的使用情况

  • 正确的行为,如果启动一个已经脱离上下文中排除,如initinetd等。

  • 设置为明智的守护程序行为的信号处理程序,也与通过用例

  • 确定的特定的处理程序重定向标准流stdinstdoutstderr因为守护进程不再有控制终端

  • 处理PID文件作为合作咨询锁,这是蠕虫的一个整体,本身有许多相互矛盾的,但有效的方式运行

  • 允许时则终止该处理

  • 实际上成为守护进程适当的清除,而不会导致僵尸

一些是标准,在典型的Unix文献(在所描述的高级编程UNIX环境,W. Richard Stevens,Addison-Wesley,1992)。其他,如流重定向和PID file handling常规行为大多数守护进程用户会期望但不那么标准化。

所有这些都由PEP 3143“标准守护进程库”规范覆盖。 python-daemon参考实现适用于Python 2.7或更高版本以及Python 3.2或更高版本。

43

请注意python-daemon包,它解决了开箱即用的守护进程背后的许多问题。

在其它特性中它能够(从Debian软件包说明):

  • 拆离的过程到它自己的进程组。
  • 设置适合在chroot中运行的进程环境。
  • 放弃suid和sgid权限。
  • 关闭所有打开的文件描述符。
  • 更改工作目录,uid,gid和umask。
  • 设置适当的信号处理程序。
  • 打开stdin,stdout和stderr的新文件描述符。
  • 管理指定的PID锁定文件。
  • 为退出处理注册清理函数。
6

YapDi是在Hacker News中弹出的一个相对较新的python模块。看起来非常有用,可用于从脚本内部将python脚本转换为守护进程模式。

86

这是我开始使用的基本'Howdy World'Python守护进程,当我开发一个新的守护进程应用程序时。

#!/usr/bin/python 
import time 
from daemon import runner 

class App(): 
    def __init__(self): 
     self.stdin_path = '/dev/null' 
     self.stdout_path = '/dev/tty' 
     self.stderr_path = '/dev/tty' 
     self.pidfile_path = '/tmp/foo.pid' 
     self.pidfile_timeout = 5 
    def run(self): 
     while True: 
      print("Howdy! Gig'em! Whoop!") 
      time.sleep(10) 

app = App() 
daemon_runner = runner.DaemonRunner(app) 
daemon_runner.do_action() 

请注意,您将需要python-daemon库。您可以通过安装它:

pip install python-daemon 

然后只需用./howdy.py start启动它,并与./howdy.py stop停止。

23

另一种方法 - 创建一个正常的非守护程序的Python程序,然后使用supervisord从外部守护进程。这可以节省许多麻烦,并且是* nix和便携式语言。

2

一个更件事想在python daemonizing时:

如果您正在使用python 记录,并要继续daemonizing后使用它,请确保调用close()的处理程序(特别是文件处理程序)。

如果你不这样做,处理程序仍然可以认为它已打开文件,并且你的消息将简单消失 - 换句话说,确保记录器知道它的文件已关闭!

这个假设当你不加区分地关闭所有打开的文件描述符时 - 而是可以尝试关闭除日志文件以外的所有文件(但通常关闭所有文件然后重新打开你想要的文件更简单)。

5

由于蟒蛇守护还不支持Python的3.x和从什么可以在邮件列表中被读取,它可能永远不会,我已经写了PEP的3143一个新的实现:pep3143daemon

pep3143daemon应支持至少python 2.6,2.7和3.x

它还包含一个PidFile类。

该库只依赖于标准库和六个模块。

它可以用作python守护进程的替代品。

这里是documentation

10

可能不是问题的直接答案,但systemd可以用来作为守护程序运行您的应用程序。这里有一个例子:

[Unit] 
Description=Python daemon 
After=syslog.target 
After=network.target 

[Service] 
Type=simple 
User=<run as user> 
Group=<run as group group> 
ExecStart=/usr/bin/python <python script home>/script.py 

# Give the script some time to startup 
TimeoutSec=300 

[Install] 
WantedBy=multi-user.target 

我喜欢这种方法,因为很多工作都是为你做的,那么你的守护进程的脚本行为类似于您的系统的其余部分。

-Orby

2

恐怕由@Dustin提到的守护进程模块并没有为我工作。相反,我安装python-daemon并用下面的代码:

# filename myDaemon.py 
import sys 
import daemon 
sys.path.append('/home/ubuntu/samplemodule') # till __init__.py 
from samplemodule import moduleclass 

with daemon.DaemonContext(): 
    moduleclass.do_running() # I have do_running() function and whatever I was doing in __main__() in module.py I copied in it. 

运行容易

> python myDaemon.py 

只是为了完整性这里是samplemodule目录内容

>ls samplemodule 
__init__.py __init__.pyc moduleclass.py 

moduleclass的内容。吡啶可以是

class moduleclass(): 
    ... 

def do_running(): 
    m = moduleclass() 
    # do whatever daemon is required to do. 
3

该函数将改变一个应用程序到守护程序:

import sys 
import os 

def daemonize(): 
    try: 
     pid = os.fork() 
     if pid > 0: 
      # exit first parent 
      sys.exit(0) 
    except OSError as err: 
     sys.stderr.write('_Fork #1 failed: {0}\n'.format(err)) 
     sys.exit(1) 
    # decouple from parent environment 
    os.chdir('/') 
    os.setsid() 
    os.umask(0) 
    # do second fork 
    try: 
     pid = os.fork() 
     if pid > 0: 
      # exit from second parent 
      sys.exit(0) 
    except OSError as err: 
     sys.stderr.write('_Fork #2 failed: {0}\n'.format(err)) 
     sys.exit(1) 
    # redirect standard file descriptors 
    sys.stdout.flush() 
    sys.stderr.flush() 
    si = open(os.devnull, 'r') 
    so = open(os.devnull, 'w') 
    se = open(os.devnull, 'w') 
    os.dup2(si.fileno(), sys.stdin.fileno()) 
    os.dup2(so.fileno(), sys.stdout.fileno()) 
    os.dup2(se.fileno(), sys.stderr.fileno()) 
1

我修改桑德马雷夏的代码示例(由@JeffBauer在the accepted answer提到的)在几行添加quit()方法在守护进程停止前执行。这有时非常有用。

Here it is.

注:我不使用“蟒蛇守护程序”模块,因为文档仍下落不明(见还有许多其他的做题),是相当模糊(如何启动/停止一个正确守护进程从这个模块的命令行?)

-1

经过几年和许多尝试,现在我认识到有一个更好的方法比想要直接从Python启动,停止,重新启动守护进程:使用操作系统工具!

而不是做python myapp startpython myapp stop总之,我这样做是为了启动应用程序:

screen -S myapp python myapp.py  
CTRL+A, D to detach 

screen -dmS myapp python myapp.pystart and detach it in one command

然后:

screen -r myapp 

再次附接至该端子。一旦进入终端,可以使用CTRL + C来停止它。