2009-05-20 20 views
9

Tôi đang làm việc trên một daemon nơi tôi cần phải nhúng một máy chủ HTTP. Tôi đang cố gắng để làm điều đó với BaseHTTPServer, khi tôi chạy nó ở phía trước, nó hoạt động tốt, nhưng khi tôi thử và nĩa daemon vào nền, nó ngừng hoạt động. Ứng dụng chính của tôi tiếp tục hoạt động, nhưng BaseHTTPServer thì không.Daemonizing BaseHTTPServer của python

Tôi tin rằng điều này có liên quan đến thực tế là BaseHTTPServer gửi dữ liệu nhật ký tới STDOUT và STDERR. Tôi đang chuyển hướng các tệp đó đến tệp. Dưới đây là đoạn mã:

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

Tôi đang làm điều gì đó sai ở đây hoặc là BaseHTTPServer bằng cách nào đó đã ngăn không cho được daemonized?

Chỉnh sửa: Đã cập nhật mã để chứng minh dòng mã bổ sung, trước đó bị thiếu và log.debug hiển thị trong nền da nền được chia hai, tôi đang nhấn mã sau ngã ba.

Trả lời

7

Sau một chút googling tôi finally stumbled over this BaseHTTPServer documentation và sau đó tôi đã kết thúc với:

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

nào cho hầu hết các phần đưa ra sau khi tôi ngã ba và kết thúc việc giải quyết các vấn đề của tôi.

0

Chỉ cần sử dụng daemontools hoặc một số tập lệnh tương tự khác thay vì lăn quá trình tạo daemon của riêng bạn. Nó là tốt hơn để giữ điều này ra khỏi kịch bản của bạn.

Ngoài ra, tùy chọn tốt nhất của bạn: Không sử dụng BaseHTTPServer. Nó thực sự là xấu. Có nhiều máy chủ HTTP tốt cho trăn, tức là cherrypy hoặc paste. Cả hai đều bao gồm các tập lệnh daemonizing sẵn sàng để sử dụng.

+1

Tại sao chính xác là BAD? xin vui lòng, đây là một trong những kết quả hàng đầu trong google ... Có một số lượng lớn các thư viện trăn dựng sẵn cho http vì vậy nhiều hơn một mô tả của những người sẽ là tuyệt vời là tốt. – nsij22

2

Bạn bắt đầu bằng cách khởi tạo một HTTPServer. Nhưng bạn không thực sự bảo nó bắt đầu phục vụ trong bất kỳ mã được cung cấp nào. Trong quá trình con của bạn, hãy thử gọi số server.serve_forever().

See this để tham khảo

+0

Trên thực tế, tôi đã chạy nó sau khi ngã ba, và theo đầu ra gỡ lỗi của tôi, sau khi ngã ba thứ hai, tôi đang nhấn mã. –

+0

Bạn nói đúng. Tôi đã chỉnh sửa câu trả lời của mình. – monowerker

4

Dưới đây là làm thế nào để làm điều này với các thư viện 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() 

Như thường lệ cho một daemon, bạn cần phải quyết định cách bạn sẽ tương tác với các chương trình sau khi nó trở thành một daemon. Ví dụ, bạn có thể đăng ký một dịch vụ systemd, hoặc viết một tập tin PID, vv Đó là tất cả bên ngoài phạm vi của câu hỏi mặc dù.

+1

Hoạt động tuyệt vời để khởi động trình tiện ích nhưng làm cách nào tôi sử dụng nó bằng các lệnh bắt đầu và dừng? Cho đến nay tôi đã không thể ngăn chặn daemon. – anno1337

+0

Làm thế nào để bạn ngăn chặn daemon này? – MohitC

0

Vì điều này đã đưa ra câu trả lời kể từ khi tôi đăng lần đầu, tôi nghĩ rằng tôi muốn chia sẻ một chút thông tin.

Vấn đề với đầu ra phải thực hiện với thực tế là trình xử lý mặc định cho mô-đun ghi nhật ký sử dụng StreamHandler. Cách tốt nhất để xử lý việc này là tạo trình xử lý của riêng bạn. Trong trường hợp bạn muốn sử dụng các module đăng nhập mặc định, bạn có thể làm một cái gì đó như thế này:

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

Cũng tại thời điểm này tôi đã chuyển sang sử dụng các dự án rất đẹp Tornado cho các máy chủ http nhúng của tôi.

1

Một giải pháp đơn giản có hiệu quả đối với tôi là ghi đè phương pháp BaseHTTPRequestHandlerlog_message(), vì vậy, chúng tôi ngăn chặn bất kỳ loại văn bản nào trong chế độ stdout và tránh các sự cố khi ẩn hình.

class CustomRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler): 

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

... 
rest of custom class code 
...