2014-06-26 100 views
1

我需要用web界面编写简单的守护进程。从python守护进程启动线程的正确方法

想法是在一个线程内使用python-daemon package并运行wsgiref.simple_server

守护程序正常工作与下面的代码:

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()启动一个线程是这样的:

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

则看起来像守护进程退出线程完成后。添加类似

while True: 
    time.sleep(1) 

web_gui()(使线程运行永远,就像一个web服务器应该)让事情变得更糟:连行web gui started日志显示不出来。

我的问题是:

  1. 为什么这不起作用?在守护进程中启动线程的正确方法是什么?
  2. 也许有更好的方法通过Web界面控制守护进程?有了这样的体系结构,我认为我应该为每个界面页面启动新的线程,这是难以扩展的。

谢谢。

回答

1

这是守护程序库的限制(discussion thread starts here)。

TL; DR:您的选项有:

  • 不要使用守护进程,因为它在这方面unrepairably打破。
  • 在“with daemoncontext”块中启动线程。

龙版本:

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

+0

配售'web.start()''之间具有上下文:'和'do_main_program'引线达到相同的结果。我会尝试http://www.jejik.com/articles/2007/02/a_simple_unix_linux_daemon_in_python/或http://supervisord.org/index.html。那么整体设计呢?可以为每个页面运行wsgi-servers线程吗? –

+0

尝试在守护程序上下文中移动创建'Thread'对象。 –

+0

将'web = threading.Thread(target = web_gui)'移至'with context:'块。没有改变。 –

0

为我工作。 你基本上想象设置守护环境就像一场额叶切断术:-)

这是我想通很容易遵循 我主要只解析参数,如果标记在后台运行,创建守护程序上下文。此后,它执行一个共同的主循环功能_main_common(),这是在一切都做,包括所创建的所有线程:

args = parse_arguments(args) 
if args.foreground: 
    # we run in the foreground, so just run the main loop 
    _main_common() 
else: 
    # we run in the background, so now create the daemon context and run the main loop 
    context = create_daemon_context(context, detach_process=True) 
    with context: 
     _main_common()