我需要用web界面编写简单的守护进程。
我的想法是使用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服务器一样)会使情况变得更糟:甚至行[{1}}也不会显示在日志中。
我的问题是:
感谢。
答案 0 :(得分:1)
这是守护程序库的限制(discussion thread starts here)。
TL; DR:你的选择是:
长版:
当守护程序库切换到守护程序上下文时,它会执行双叉。这意味着它首先分叉然后杀死父进程。新的fork没有任何线程,因此退出父进程等同于杀死webgui线程。最终,此问题的任何解决方案都必须在新创建的子进程中启动任何永久线程。在守护程序上下文中执行此操作的缺点是您不再能够将潜在错误传播给用户。理想情况下,你是双叉,但不要退出父进程,然后设置你的守护进程,然后在进入主循环之前让父进程退出。使用守护程序库或任何实现PEP3143草稿的库无法实现这一点。
答案 1 :(得分:0)
为我工作。 你基本上不得不想象设置守护进程上下文就像一个额叶切除术:-)
以下是我认为很容易理解的内容 我的 main 仅解析参数,如果标记为在后台运行,则创建守护进程上下文。此后,它执行一个公共主循环函数_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()