从python守护进程启动线程的正确方法 [英] Proper way to start thread from python daemon

查看:114
本文介绍了从python守护进程启动线程的正确方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要使用Web界面编写简单的守护程序。

I need to write simple daemon with web interface.

想法是使用 python-daemon程序包,然后在一个线程内运行 wsgiref.simple_server

The idea is to use python-daemon package and run wsgiref.simple_server inside one thread.

守护程序可以在以下代码中正常工作:

Daemon works fine with the following code :

import daemon
import logging
import time
import signal
import threading

logfilename = '/var/log/testdaemon.log'
logger = logging.getLogger("DaemonLog")
logger.setLevel(logging.INFO)
formatter = logging.Formatter(
    '%(asctime)s:%(levelname)s:%(message)s',
    '%Y-%m-%d %H:%M:%S')
handler = logging.FileHandler(logfilename)
handler.setFormatter(formatter)
logger.addHandler(handler)

def initial_program_setup():
    logger.info('daemon started')

def do_main_program():
    while True:
        time.sleep(1)
        logger.info('another second passed')

def program_cleanup(signum, frame):
    logger.info('daemon stops')
    context.terminate(signum, frame)

def reload_program_config(signum, frame):
    logger.info('reloading config')

context = daemon.DaemonContext()

context.signal_map = {
    signal.SIGTERM: program_cleanup,
    signal.SIGHUP: 'terminate',
    signal.SIGUSR1: reload_program_config,
    }

context.files_preserve = [handler.stream]

initial_program_setup()

with context:
    do_main_program()

但是,如果我在 initial_program_setup()中启动线程,则这样:

But if I start a thread in initial_program_setup() like this :

def web_gui():
    logger.info('weg gui started')

web = threading.Thread(target=web_gui)
web.setDaemon(True)

def initial_program_setup():
    logger.info('daemon started')
    web.start()

然后看起来就像守护进程在线程完成后退出。添加类似内容

then looks like daemon exits after thread completes. Adding something like

while True:
    time.sleep(1)

web_gui()(以使线程永远运行,就像网络服务器应该的那样)使情况变得更糟:即使开始行行$ 也不会显示在日志中。

to web_gui() (to make thread run forever, like a web server should) makes it even worse: even the line web gui started doesn't show up in log.

我的问题是:


  1. 为什么这不起作用?在守护程序中启动线程的正确方法是什么?

  2. 也许有更好的方法可以通过Web界面控制守护程序?有了这样的架构,我认为我应该为每个界面页面启动一个新线程,这很难扩展。

谢谢。

推荐答案

这是一个限制(讨论线程从守护进程库开始()。

TL; DR :您的选择是:

TL;DR: Your options are:


  • 不要使用守护程序,因为它在这方面不可修复地损坏。

  • 在 with daemoncontext块中启动线程。

长版本:

当守护程序库切换到守护程序上下文时,它会进行两次分叉。这意味着它首先分叉,然后杀死父进程。一个新的fork没有任何线程,因此退出父进程就等于杀死您的webgui线程。最终,任何解决此问题的方法都必须在新创建的子进程中启动任何永久线程。在守护程序上下文中执行此操作的缺点是您不再能够将潜在的错误传播给用户。理想情况下,您会使用双叉,但不要退出父进程,然后设置守护程序,然后在进入主循环之前立即退出父进程。这是守护程序库或任何实现PEP3143草案的库无法实现的。

When the daemon library switches to daemon context, it does a double-fork. That means it first forks and then kills the parent process. A new fork does not have any thread, so exiting the parent process equates killing your webgui thread. Ultimately, any solution to this problem must start any permanent threads in the newly created child process. The downside of doing this in the daemon context is that you are no longer able to propagate potential errors to the user. Ideally you'd double-fork, but do not exit the parent process, then set up your daemon and right before entering the main loop make the parent process exit. This is not achievable with the daemon library or any library implementing the PEP3143 draft.

这篇关于从python守护进程启动线程的正确方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆