2014-06-26 155 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()