我写了一个Python脚本,检查一个特定的电子邮件地址,并将新的电子邮件传递给一个外部程序。如何让这个脚本全天候执行,比如在Linux中将其转换为守护进程或服务。我是否还需要一个在程序中永不结束的循环,或者可以通过多次重新执行代码来完成?


当前回答

如果你正在使用终端(ssh或其他东西),并且你想在退出终端后保持长时间的脚本工作,你可以尝试这样做:

屏幕

Apt-get安装屏幕

在里面创建一个虚拟终端(即abc): screen -dmS abc

现在我们连接到abc: screen -r abc

因此,现在我们可以运行python脚本:python keep_sending_mail .py

从现在开始,你可以直接关闭你的终端,但是,python脚本将继续运行而不是被关闭

因为这个keep_sending_mail .py的PID是虚拟屏幕的子进程,而不是 终端(ssh)

如果你想检查你的脚本运行状态,你可以再次使用screen -r abc

其他回答

我推荐这个解决方案。您需要继承和重写方法运行。

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()

cron is clearly a great choice for many purposes. However it doesn't create a service or daemon as you requested in the OP. cron just runs jobs periodically (meaning the job starts and stops), and no more often than once / minute. There are issues with cron -- for example, if a prior instance of your script is still running the next time the cron schedule comes around and launches a new instance, is that OK? cron doesn't handle dependencies; it just tries to start a job when the schedule says to.

如果您发现确实需要一个守护进程(一个永不停止运行的进程),请查看一下监控器。它提供了一种简单的方法来包装普通的、非守护进程化的脚本或程序,并使其像守护进程一样运行。这比创建本地Python守护进程好得多。

如果你正在使用终端(ssh或其他东西),并且你想在退出终端后保持长时间的脚本工作,你可以尝试这样做:

屏幕

Apt-get安装屏幕

在里面创建一个虚拟终端(即abc): screen -dmS abc

现在我们连接到abc: screen -r abc

因此,现在我们可以运行python脚本:python keep_sending_mail .py

从现在开始,你可以直接关闭你的终端,但是,python脚本将继续运行而不是被关闭

因为这个keep_sending_mail .py的PID是虚拟屏幕的子进程,而不是 终端(ssh)

如果你想检查你的脚本运行状态,你可以再次使用screen -r abc

您还可以使用shell脚本使python脚本作为服务运行。首先创建一个shell脚本,像这样运行python脚本(scriptname任意名称)

#!/bin/sh
script='/home/.. full path to script'
/usr/bin/python $script &

现在在/etc/init.d/scriptname中创建一个文件

#! /bin/sh

PATH=/bin:/usr/bin:/sbin:/usr/sbin
DAEMON=/home/.. path to shell script scriptname created to run python script
PIDFILE=/var/run/scriptname.pid

test -x $DAEMON || exit 0

. /lib/lsb/init-functions

case "$1" in
  start)
     log_daemon_msg "Starting feedparser"
     start_daemon -p $PIDFILE $DAEMON
     log_end_msg $?
   ;;
  stop)
     log_daemon_msg "Stopping feedparser"
     killproc -p $PIDFILE $DAEMON
     PID=`ps x |grep feed | head -1 | awk '{print $1}'`
     kill -9 $PID       
     log_end_msg $?
   ;;
  force-reload|restart)
     $0 stop
     $0 start
   ;;
  status)
     status_of_proc -p $PIDFILE $DAEMON atd && exit 0 || exit $?
   ;;
 *)
   echo "Usage: /etc/init.d/atd {start|stop|restart|force-reload|status}"
   exit 1
  ;;
esac

exit 0

现在可以使用/etc/init.命令启动和停止python脚本D /scriptname start or stop。

一个简单且受支持的版本是Daemonize。

从Python包索引(PyPI)安装它:

$ pip install daemonize

然后用like:

...
import os, sys
from daemonize import Daemonize
...
def main()
      # your code here

if __name__ == '__main__':
        myname=os.path.basename(sys.argv[0])
        pidfile='/tmp/%s' % myname       # any name
        daemon = Daemonize(app=myname,pid=pidfile, action=main)
        daemon.start()