如何在Linux中将Python脚本运行如同服务或守护进程

226

我编写了一个Python脚本,用于检查某个电子邮件地址并将新的电子邮件传递给外部程序。如何使此脚本在Linux中成为守护进程或服务并24/7运行?是否需要在程序中添加不断循环的代码,还是可以通过多次重新执行代码来实现?


1
请参阅以下问题:https://dev59.com/LXM_5IYBdhLWcg3wUxjF - mjv
3
检查特定的电子邮件地址并将新的电子邮件传递给外部程序。这不是sendmail所做的吗?您可以定义邮件别名将邮箱路由到脚本。为什么不使用邮件别名来完成这个任务呢? - S.Lott
2
在拥有 systemd 的现代 Linux 上,您可以按照此处所述的方式创建一个以 daemon 模式运行的 systemd 服务。另请参阅:https://www.freedesktop.org/software/systemd/man/systemd.service.html - ccpizza
如果Linux系统支持systemd,请使用此方法在此处概述 - gerardw
16个回答

8
如果您正在使用终端(ssh或其他),并且希望在退出终端后保持长时间运行的脚本,请尝试以下操作:
安装screen: apt-get install screen 创建一个名为abc的虚拟终端:screen -dmS abc 现在连接到abc:screen -r abc 现在,我们可以运行Python脚本:python keep_sending_mails.py 从此以后,您可以直接关闭终端,但是Python脚本将继续运行而不被关闭。
由于这个keep_sending_mails.py的PID是虚拟屏幕而不是终端(ssh)的子进程,
如果您想回去检查您的脚本运行状态,可以再次使用screen -r abc

2
虽然这个方法可以工作,但它非常简单粗暴,应该在生产环境中避免使用。 - pcnate

4
首先,了解一下邮件别名。一个邮件别名可以在邮件系统内部完成此操作,而无需您使用守护程序、服务或任何其他类似的东西。

您可以编写一个简单的脚本,每次向特定邮箱发送邮件时都会被sendmail执行。

请参见 http://www.feep.net/sendmail/tutorial/intro/aliases.html

如果您真的想编写一个毫无必要的复杂服务器,您可以这样做。

nohup python myscript.py &

这就是全部所需。您的脚本只需要循环和休眠即可。
import time
def do_the_work():
    # one round of polling -- checking email, whatever.
while True:
    time.sleep( 600 ) # 10 min.
    try:
        do_the_work()
    except:
        pass

6
问题在于do_the_work()可能会导致脚本崩溃,没有人会再次运行它。 - Ivan Nevostruev
如果函数 do_the_work() 崩溃,则在 10 分钟后将再次调用它,因为仅有一个函数调用引发了错误。但是,循环不会崩溃,只有“try”部分失败,然后将调用“except:”部分(在这种情况下为无),但循环将继续并继续尝试调用该函数。 - Lukr

3
我会推荐这个解决方案。你需要继承并重写方法run
import sys
import os
from signal import SIGTERM
from abc import ABCMeta, abstractmethod



class Daemon(object):
    __metaclass__ = ABCMeta


    def __init__(self, pidfile):
        self._pidfile = pidfile


    @abstractmethod
    def run(self):
        pass


    def _daemonize(self):
        # decouple threads
        pid = os.fork()

        # stop first thread
        if pid > 0:
            sys.exit(0)

        # write pid into a pidfile
        with open(self._pidfile, 'w') as f:
            print >> f, os.getpid()


    def start(self):
        # if daemon is started throw an error
        if os.path.exists(self._pidfile):
            raise Exception("Daemon is already started")

        # create and switch to daemon thread
        self._daemonize()

        # run the body of the daemon
        self.run()


    def stop(self):
        # check the pidfile existing
        if os.path.exists(self._pidfile):
            # read pid from the file
            with open(self._pidfile, 'r') as f:
                pid = int(f.read().strip())

            # remove the pidfile
            os.remove(self._pidfile)

            # kill daemon
            os.kill(pid, SIGTERM)

        else:
            raise Exception("Daemon is not started")


    def restart(self):
        self.stop()
        self.start()

旧帖子,但是我如何在树莓派上使用和安装这个守护程序? - WWebber

2

如果您想创建类似服务的东西,可以使用以下内容:

首先,您必须安装Cement框架: Cement框架是一个CLI框架,您可以在其中部署应用程序。

应用程序的命令行界面为:

interface.py

 from cement.core.foundation import CementApp
 from cement.core.controller import CementBaseController, expose
 from YourApp import yourApp

 class Meta:
    label = 'base'
    description = "your application description"
    arguments = [
        (['-r' , '--run'],
          dict(action='store_true', help='Run your application')),
        (['-v', '--version'],
          dict(action='version', version="Your app version")),
        ]
        (['-s', '--stop'],
          dict(action='store_true', help="Stop your application")),
        ]

    @expose(hide=True)
    def default(self):
        if self.app.pargs.run:
            #Start to running the your app from there !
            YourApp.yourApp()
        if self.app.pargs.stop:
            #Stop your application
            YourApp.yourApp.stop()

 class App(CementApp):
       class Meta:
       label = 'Uptime'
       base_controller = 'base'
       handlers = [MyBaseController]

 with App() as app:
       app.run()

YourApp.py类:

 import threading

 class yourApp:
     def __init__:
        self.loger = log_exception.exception_loger()
        thread = threading.Thread(target=self.start, args=())
        thread.daemon = True
        thread.start()

     def start(self):
        #Do every thing you want
        pass
     def stop(self):
        #Do some things to stop your application

请记住,你的应用程序必须在线程上运行才能成为守护进程。
要运行该应用程序,请在命令行中执行以下操作:

python interface.py --help


1
你可以像这样在脚本内或另一个脚本中作为子进程运行进程。
subprocess.Popen(arguments, close_fds=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, stdin=subprocess.DEVNULL)

或者使用现成的工具

https://github.com/megashchik/d-handler


1

使用系统提供的任何服务管理器 - 例如在Ubuntu下使用upstart。这将为您处理所有细节,如启动时自动启动,崩溃后重新启动等。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接