2009-05-20 82 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 
...