2009-05-20 31 views
9

我正在一个守护进程中,我需要嵌入一个HTTP服务器。我试图用BaseHTTPServer来完成它,当我在前台运行它时,它可以正常工作,但是当我尝试将守护进程分叉到后台时,它停止工作。我的主应用程序继续工作,但BaseHTTPServer没有。守护python的BaseHTTPServer

我认为这与BaseHTTPServer将日志数据发送到STDOUT和STDERR的事实有关。我将这些文件重定向到文件。这里是代码片段:

# Start the HTTP Server 
server = HTTPServer((config['HTTPServer']['listen'],config['HTTPServer']['port']),HTTPHandler) 

# Fork our process to detach if not told to stay in foreground 
if options.foreground is False: 
    try: 
     pid = os.fork() 
     if pid > 0: 
      logging.info('Parent process ending.') 
      sys.exit(0)    
    except OSError, e: 
     sys.stderr.write("Could not fork: %d (%s)\n" % (e.errno, e.strerror)) 
     sys.exit(1) 

    # Second fork to put into daemon mode 
    try: 
     pid = os.fork() 
     if pid > 0: 
      # exit from second parent, print eventual PID before 
      print 'Daemon has started - PID # %d.' % pid 
      logging.info('Child forked as PID # %d' % pid) 
      sys.exit(0) 
    except OSError, e: 
     sys.stderr.write("Could not fork: %d (%s)\n" % (e.errno, e.strerror)) 
     sys.exit(1) 


    logging.debug('After child fork') 

    # Detach from parent environment 
    os.chdir('/') 
    os.setsid() 
    os.umask(0) 

    # Close stdin  
    sys.stdin.close() 

    # Redirect stdout, stderr 
    sys.stdout = open('http_access.log', 'w') 
    sys.stderr = open('http_errors.log', 'w')  

# Main Thread Object for Stats 
threads = [] 

logging.debug('Kicking off threads') 

while ... 
    lots of code here 
... 

server.serve_forever() 

我在这里做错了什么或是BaseHTTPServer以某种方式防止成为守护进程?

编辑:更新后的代码来演示额外的,以前缺少的代码流,并且log.debug显示在fork后面的后台守护进程中。

回答

7

有点谷歌上搜索我finally stumbled over this BaseHTTPServer documentation后之后,我结束了:

from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer 
from SocketServer import ThreadingMixIn 

class ThreadedHTTPServer(ThreadingMixIn, HTTPServer): 
    """Handle requests in a separate thread.""" 

server = ThreadedHTTPServer((config['HTTPServer']['listen'],config['HTTPServer']['port']), HTTPHandler) 
server.serve_forever() 

其中大部分后我叉和最终解决我的问题就来了。

0

只需使用daemontools或其他类似的脚本代替滚动自己的守护进程。关闭脚本好得多。

另外,您最好的选择:不要使用BaseHTTPServer。这真的很糟糕。 Python有很多好的HTTP服务器,即cherrypypaste。两者都包含随时可用的守护程序脚本。

+1

为什么它不好?请,这是谷歌的顶级成果之一......有大量的预建python库的http,所以更多的描述这些将是惊人的。 – nsij22 2015-05-19 03:33:23

2

您首先实例化一个HTTPServer。但你实际上并没有告诉它在任何提供的代码中开始提供服务。在你的孩子的过程中,尝试拨打server.serve_forever()

See this参考

+0

其实,我是在fork之后运行的,根据我的调试输出,在第二个fork之后,我正在打代码。 – 2009-05-20 17:19:39

+0

你说得对。我编辑了我的答案。 – monowerker 2009-05-20 17:24:06

4

下面是如何与python-daemon库做到这一点:

from BaseHTTPServer import (HTTPServer, BaseHTTPRequestHandler) 
import contextlib 

import daemon 

from my_app_config import config 

# Make the HTTP Server instance. 
server = HTTPServer(
    (config['HTTPServer']['listen'], config['HTTPServer']['port']), 
    BaseHTTPRequestHandler) 

# Make the context manager for becoming a daemon process. 
daemon_context = daemon.DaemonContext() 
daemon_context.files_preserve = [server.fileno()] 

# Become a daemon process. 
with daemon_context: 
    server.serve_forever() 

像往常一样的守护进程,你需要决定你将如何使用该程序就变成了守护程序后进行交互。例如,你可能会注册一个systemd服务,或者写一个PID文件等。这些都在问题的范围之外。

0

既然我自从发布以来就征求了答案,我以为我会分享一些信息。

输出问题与记录模块的默认处理程序使用StreamHandler有关。处理这个问题的最好方法是创建自己的处理程序。在您要使用默认的日志模块的情况下,你可以做这样的事情:

# Get the default logger 
default_logger = logging.getLogger('') 

# Add the handler 
default_logger.addHandler(myotherhandler) 

# Remove the default stream handler 
for handler in default_logger.handlers: 
    if isinstance(handler, logging.StreamHandler): 
     default_logger.removeHandler(handler) 

此外,在这一点上我已经转移到使用非常漂亮Tornado项目为我的嵌入式HTTP服务器。

1

一个简单的解决方案,为我工作是覆盖BaseHTTPRequestHandler方法log_message(),所以我们阻止任何类型的标准输出,并避免在恶化时的问题。

class CustomRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler): 

    def log_message(self, format, *args): 
      pass 

... 
rest of custom class code 
...