我正在开发一个需要嵌入HTTP服务器的守护进程。我正在尝试使用BaseHTTPServer,当我在前台运行它时,它工作正常,但是当我尝试将守护进程分叉到后台时,它会停止工作。我的主要应用程序继续工作,但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之后命中代码。
答案 0 :(得分: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()
在我解决问题之后,大部分时间都来了。
答案 1 :(得分:3)
以下是使用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文件等。但这些都超出了问题的范围。
答案 2 :(得分:2)
首先实例化HTTPServer。但实际上并没有告诉它开始提供任何提供的代码。在您的子流程中,请尝试拨打server.serve_forever()
。
See this以供参考
答案 3 :(得分:1)
一个对我有用的简单解决方案是覆盖BaseHTTPRequestHandler
方法log_message()
,因此我们会阻止stdout中的任何类型的写入,并在妖魔化时避免出现问题。
class CustomRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
def log_message(self, format, *args):
pass
...
rest of custom class code
...
答案 4 :(得分:0)
只需使用daemontools或其他类似的脚本,而不是滚动自己的守护进程。把它从剧本中删除会好得多。
此外,您最好的选择:不要使用BaseHTTPServer。真的很糟糕。 python有许多优秀的HTTP服务器,即cherrypy或paste。两者都包括随时可用的守护程序脚本。
答案 5 :(得分: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服务器。