如何建立与蟒蛇守护守护进程?(How do I set up a daemon with pytho

2019-07-02 18:45发布

我是新来的守护进程,这样的道歉,如果这是一个新手的问​​题。

在其他几个答案(例如, 这个问题 )的人提出的蟒蛇守护包得去,因为它完全实现了道路PEP 3143标准。

不幸的是,蟒蛇守护程序是对文件有点轻 (或更可能我的知识/经验......略显清淡;)),我想我可能真的缺少基本的东西。 下面是我在做什么:

我有以下几点:

import daemon

logfile = open('daemon.log', 'w')

context = daemon.DaemonContext(stdout = logfile, stderr = logfile)

context.open()

with context:
    do_something_1()
    do_something_2()

问:如何建立与蟒蛇守护守护进程,我怎么能启动和停止它?


旁注:

我基本上采取有关如何/是否胡乱猜测.open()应在此处使用方法-文档并没有在这一点上真正明确。 同样的事情似乎发生我是否包含与否。

所以,现在我该怎么办? 当我尝试运行此文件,如:

python startConsumerDaemons.py

它似乎运行do_something_1()而不是第二。 而且,它似乎离开附着在终端窗口的程序。 IE,标准输出不重定向,并且当我关闭终端窗口过程被中止。 所以,我敢肯定,我在这里做得不对......我应该怎么做不同?

而且,最后,一旦我得到的守护进程,我怎么停止/重新启动(例如,如果我做出改变底层代码)?

Answer 1:

这里是我有什么,这对我的作品。 它也有一个SysV初始化脚本。 回购是在GitHub上 ,我也有一个简短的博客文章链接到其他可能的解决方案,我发现。

只能有一个守护进程在运行:即由PID锁定文件管理,像大多数其他的Linux守护程序。 要停止它,做

kill `cat /var/run/eg_daemon.pid`

要查看是否正在运行:

ps -elf | grep `cat /var/run/eg_daemon.pid`

使用子模块了pidfile,PID文件是自动管理。 当守护程序停止使用时,pidfile被清除了。 请参阅链接的GitHub库为init脚本。

下面是Python的守护进程的代码:

#!/usr/bin/env python3.5
import sys
import os
import time
import argparse
import logging
import daemon
from daemon import pidfile

debug_p = False

def do_something(logf):
    ### This does the "work" of the daemon

    logger = logging.getLogger('eg_daemon')
    logger.setLevel(logging.INFO)

    fh = logging.FileHandler(logf)
    fh.setLevel(logging.INFO)

    formatstr = '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
    formatter = logging.Formatter(formatstr)

    fh.setFormatter(formatter)

    logger.addHandler(fh)

    while True:
        logger.debug("this is a DEBUG message")
        logger.info("this is an INFO message")
        logger.error("this is an ERROR message")
        time.sleep(5)


def start_daemon(pidf, logf):
    ### This launches the daemon in its context

    ### XXX pidfile is a context
    with daemon.DaemonContext(
        working_directory='/var/lib/eg_daemon',
        umask=0o002,
        pidfile=pidfile.TimeoutPIDLockFile(pidf),
        ) as context:
        do_something(logf)


if __name__ == "__main__":
    parser = argparse.ArgumentParser(description="Example daemon in Python")
    parser.add_argument('-p', '--pid-file', default='/var/run/eg_daemon.pid')
    parser.add_argument('-l', '--log-file', default='/var/log/eg_daemon.log')

    args = parser.parse_args()

    start_daemon(pidf=args.pid_file, logf=args.log_file)

为了完整起见,这里是init脚本。 需要注意的是“杀”实际上只是用于发送POSIX信号的方法 - 见信号手册(7)的概述。 蟒蛇守护进程方面将赶上信号,终止合理的关闭文件描述符的过程,并自动删除PID文件。 因此,它确实是一个干净的终止。

你可以写你的代码,以赶上SIGUSR1或类似的东西,为了做守护程序配置的重新加载。 有没有优势,编写Python停止守护进程。

#!/bin/bash
#
# eg_daemon      Startup script for eg_daemon
#
# chkconfig: - 87 12
# description: eg_daemon is a dummy Python-based daemon
# config: /etc/eg_daemon/eg_daemon.conf
# config: /etc/sysconfig/eg_daemon
# pidfile: /var/run/eg_daemon.pid
#
### BEGIN INIT INFO
# Provides: eg_daemon
# Required-Start: $local_fs
# Required-Stop: $local_fs
# Short-Description: start and stop eg_daemon server
# Description: eg_daemon is a dummy Python-based daemon
### END INIT INFO

# Source function library.
. /etc/rc.d/init.d/functions

if [ -f /etc/sysconfig/eg_daemon ]; then
        . /etc/sysconfig/eg_daemon
fi

eg_daemon=/var/lib/eg_daemon/eg_daemon.py
prog=eg_daemon
pidfile=${PIDFILE-/var/run/eg_daemon.pid}
logfile=${LOGFILE-/var/log/eg_daemon.log}
RETVAL=0

OPTIONS=""

start() {
        echo -n $"Starting $prog: "

        if [[ -f ${pidfile} ]] ; then
            pid=$( cat $pidfile  )
            isrunning=$( ps -elf | grep  $pid | grep $prog | grep -v grep )

            if [[ -n ${isrunning} ]] ; then
                echo $"$prog already running"
                return 0
            fi
        fi
        $eg_daemon -p $pidfile -l $logfile $OPTIONS
        RETVAL=$?
        [ $RETVAL = 0 ] && success || failure
        echo
        return $RETVAL
}

stop() {
    if [[ -f ${pidfile} ]] ; then
        pid=$( cat $pidfile )
        isrunning=$( ps -elf | grep $pid | grep $prog | grep -v grep | awk '{print $4}' )

        if [[ ${isrunning} -eq ${pid} ]] ; then
            echo -n $"Stopping $prog: "
            kill $pid
        else
            echo -n $"Stopping $prog: "
            success
        fi
        RETVAL=$?
    fi
    echo
    return $RETVAL
}

reload() {
    echo -n $"Reloading $prog: "
    echo
}

# See how we were called.
case "$1" in
  start)
    start
    ;;
  stop)
    stop
    ;;
  status)
    status -p $pidfile $eg_daemon
    RETVAL=$?
    ;;
  restart)
    stop
    start
    ;;
  force-reload|reload)
    reload
    ;;
  *)
    echo $"Usage: $prog {start|stop|restart|force-reload|reload|status}"
    RETVAL=2
esac

exit $RETVAL


Answer 2:

完整的例子就是可以在这里找到 。

你应该能够更好地了解蟒蛇守护程序的内部工作。

此外还提供了代码给出了一个初始化脚本,直接开始/停止守护进程的一个例子。 但是,你可以启动/简单地通过使用stop参数来再次调用原有的功能停止:

python original_func.py stop


Answer 3:

As you can see in the 'with' statement documentation, it statement does perform some 'magic', which is related to our purpose. Specifically:

The execution of the with statement with one “item” proceeds as follows:

  1. The context expression (the expression given in the with_item) is evaluated to obtain a context manager.

  2. The context manager’s __exit__() is loaded for later use.

  3. he context manager’s __enter__() method is invoked.

  4. If a target was included in the with statement, the return value from __enter__() is assigned to it.

  5. The suite is executed.

  6. The context manager’s __exit__() method is invoked. If an exception caused the suite to be exited, its type, value, and traceback are passed as arguments to __exit__(). Otherwise, three None arguments are supplied.

What does this mean? If you look closely to the PEP in question, which serves as python-daemon documentation as well (and which indeed could be much improved), you'll see that it implements __enter__() and __exit__():

The class also implements the context manager protocol via __enter__ and __exit__ methods.

__enter__()

Call the instance's open() method, then return the instance.

__exit__(exc_type, exc_value, exc_traceback)

Call the instance's close() method, then return True if the exception was handled or False if it was not.

In other words, open() is not needed, the example given in the PEP (though not explained correctly) works as is. While the with statement does mean something, it does not keep any loop, once the end of its scope is reached, it calls exit(), which in python-daemon means close(). Therefore, you need to put there a while True or which ever infinite loop you consider.

On behave of your second script not working, I can't really tell you, I'm surprised the first already works. If your daemon is stopping, there is a problem with your scripts for sure, you can check your consumerDaemonLogFile. (as a side note, you have a typo 'sderr' --> 'stderr')

Also, you can see in the PEP that if not specified, the working directory property defaults to '/'. this might be the source of your problem if you are using relative paths in your scripts.

Finally, about the last question, you can easily kill you're daemon finding its PID:

ps ax | grep startConsumerDaemons.py

and sending it a SIGTERM:

kill <pid>

The answer provided by gromain does provide a more handy way to start and stop it, with 'daemon.runner()', but it's far more complicated to setup.



Answer 4:

在Linux上,你可以通过运行停止守护程序:

$ ps -x

并查找对应于您的守护进程,然后就杀死进程的PID。



Answer 5:

一个有用的文件仍然缺少的模块“蟒蛇守护”。 我个人放弃了如何使用它,现在我成功地使用桑德马雷夏尔的守护程序代码在这个答案引用 。

我为了能当你调用做事情稍微修改了它python testdaemon.py stop

下面是代码 。


用法示例:

import sys, daemon, time

class testdaemon(daemon.Daemon):
    def run(self):
        self.i = 0
        with open('test1.txt', 'w') as f:
            f.write(str(self.i))
        while True:
            self.i += 1
            time.sleep(1)

    def quit(self):
        with open('test2.txt', 'w') as f:
            f.write(str(self.i))

daemon = testdaemon()

if 'start' == sys.argv[1]: 
    daemon.start()
elif 'stop' == sys.argv[1]: 
    daemon.stop()
elif 'restart' == sys.argv[1]: 
    daemon.restart()


Answer 6:

daemon.DaemonContext构造函数接受一个lockfile的选项。 使用锁文件库,将记录进程的PID。

图书馆最初推荐lockfile.PIDLockFile类,但库现在已经过时,没有一个很好的替代。 但是你可以实现与相同的语义的另一个对象。

然后,进程的PID是通过读取指定PID文件的内容简单地找到。 使用PID将信号发送到运行中的进程。



文章来源: How do I set up a daemon with python-daemon?