如何运行长期(无限)Python进程?

时间:2011-12-31 01:39:40

标签: python apache daemon infinite-loop

我最近开始尝试使用Python进行Web开发。到目前为止,我已经使用Apache与mod_wsgi和用于Python 2.7的Django Web框架取得了一些成功。但是,我遇到了一些问题,即流程不断运行,更新信息等等。

我编写了一个名为“daemonManager.py”的脚本,可以启动和停止所有或单个python更新循环(我应该称之为守护进程?)。它通过分叉,然后为应该运行的特定函数加载模块并启动无限循环来实现。它会在/var/run中保存PID文件以跟踪进程。到现在为止还挺好。我遇到的问题是:

  • 偶尔会退出其中一个进程。我早上检查ps,过程刚刚结束。没有记录任何错误(我正在使用logging模块),我正在涵​​盖我能想到的每个异常并记录它们。此外,我不认为这些退出过程与我的代码有任何关系,因为我的所有进程都运行完全不同的代码并以非常相似的间隔退出。我当然错了。 Python进程在运行数天/数周后死亡是否正常?我该如何解决这个问题?我应该编写另一个守护进程来定期检查其他守护进程是否仍在运行吗?如果守护进程停止怎么办?我对如何处理这件事感到茫然。

  • 如何以编程方式知道进程是否仍在运行?我将PID文件保存在/var/run中,并检查PID文件是否在那里以确定进程是否正在运行。但是如果进程刚刚因意外原因而死,则PID文件将保留。因此,每次进程崩溃(每周几次)时,我都必须删除这些文件,这会破坏目的。我想我可以检查一个进程是否正在文件中的PID上运行,但如果另一个进程已启动并被分配了死进程的PID怎么办?我的守护进程会认为这个进程运行正常,即使它已经很久了。我再次对如何解决这个问题感到茫然。

关于如何最好运行无限Python进程的任何有用答案,希望也能解决上述问题,我会接受


我在Ubuntu机器上使用Apache 2.2.14 我的Python版本是2.7.2

3 个答案:

答案 0 :(得分:26)

我将通过声明这是一种管理长时间运行流程(LRP)的方式打开 - 不是事实上的任何延伸。

根据我的经验,最好的产品来自于专注于您正在处理的特定问题,同时将支持技术委托给其他图书馆。在这种情况下,我指的是后台进程(双叉的艺术),监视和日志重定向的行为。

我最喜欢的解决方案是http://supervisord.org/

使用像supervisord这样的系统,你基本上可以编写一个传统的python脚本来执行任务,同时陷入“无限”循环。

#!/usr/bin/python

import sys
import time

def main_loop():
    while 1:
        # do your stuff...
        time.sleep(0.1)

if __name__ == '__main__':
    try:
        main_loop()
    except KeyboardInterrupt:
        print >> sys.stderr, '\nExiting by user request.\n'
        sys.exit(0)

以这种方式编写脚本使得开发和调试变得简单方便(您可以在终端中轻松启动/停止它,在事件展开时观察日志输出)。当投入生产时,您只需定义一个调用脚本的超级用户配置(这里是用于定义“程序”的完整示例,其中大部分是可选的:http://supervisord.org/configuration.html#program-x-section-example

主管有一堆的配置选项,所以我不会枚举它们,但我会说它专门解决了你描述的问题:

  • Backgrounding / Daemonizing
  • PID跟踪(可以配置为在意外终止时重新启动进程)
  • 通常在您的脚本中记录(流处理程序,如果使用日志记录模块而不是打印),但让管理员重定向到您的文件。

答案 1 :(得分:2)

我假设您正在运行Unix / Linux,但您并没有真正说出来。我对你的问题没有直接的建议。所以我不希望成为这个问题的“正确”答案。但这里有一些值得探索的东西。

首先,如果你的守护进程崩溃了,你应该解决这个问题。只有带错误的程序才会崩溃。也许您应该在调试器下启动它们,看看它们崩溃时会发生什么(如果可能的话)。您是否在这些流程中有任何跟踪记录?如果没有,请添加它们。这可能有助于诊断您的崩溃。

其次,您的守护进程是提供服务(打开管道和等待请求)还是执行定期清理?如果它们是定期清理过程,你应该使用cron定期启动它们,而不是让它们在无限循环中运行。 Cron进程应优先于守护进程。同样,如果它们是打开端口和服务请求的服务,您是否考虑过让它们与INETD一起使用?同样,单个守护进程(inetd)应该优先于一堆守护进程。

第三,正如您所发现的那样,将PID保存在文件中并不是非常有效。也许像信号量一样的共享IPC可以更好地工作。我虽然没有任何细节。

第四,有时候我需要在网站的上下文中运行。我使用一个用维护URL调用wget的cron进程。您设置了一个特殊的cookie,并在wget命令行中包含cookie信息。如果特殊cookie不存在,则返回403而不是执行维护过程。这里的另一个好处是登录数据库以及避免的其他环境问题,因为为普通网页提供服务的代码正在为维护过程服务。

希望能给你一些想法。我认为如果可以的话,避免使用守护进程是最好的起点。如果你可以在mod_wsgi中运行你的python,这可以节省你必须支持多个“环境”。调试一次运行几天后失败的进程只是残酷的。

答案 2 :(得分:2)

假设您的程序,Python解释器或您正在使用的任何Python库/模块中没有任何内存泄漏,您应该认为Python进程能够“永远”运行。 (即使在内存泄漏的情况下,如果你在64位机器上有足够的交换空间,你也许可以永远运行。几十年,如果不是几个世纪,应该是可行的。我已经让Python进程幸存下来了。在硬件有限的两年 - 在需要移动硬件之前。)

当使用Linux发行版SysV-style init时,确保程序重新启动时非常简单 - 只需向/etc/inittab添加新行,init(8)将生成您的程序启动并重新生成它,如果它死了。 (我知道没有机制可以使用新的upstart init来复制此功能 - 许多发行版现在正在使用它的替换。我不是说这是不可能的,我只是不知道如何做吧。)

但即便过去几年的init(8)机制也不如某些人所希望的那样灵活。 DJB的daemontools包是过程控制和监视工具的一个例子,旨在让守护进程永远存在。 Linux-HA套件提供了另一个类似的工具,但它可能提供了太多的“额外”功能,无法为此任务辩护。 monit是另一种选择。