Python atexit 在不同进程中清理服务器 — 端口仍在使用中
我有一些集成测试的代码,它会在一个不同的进程中启动一个HTTP服务器,以便进行调用。这个服务器可能会因为活动而受到影响,所以我希望能随时启动和停止新的实例。
但不幸的是,这个方法没有奏效……我遇到了一个问题,就是我的服务器运行的端口在我的进程退出后仍然被锁定(这意味着如果我快速运行两次测试,第二次会失败,因为端口被锁住了)。
我尝试使用 atexit.register
来绑定关闭方法,但也没有成功。
这是服务器的代码:
from BaseHTTPServer import BaseHTTPRequestHandler
import SocketServer
import atexit
class RestHTTPRequestHandler(BaseHTTPRequestHandler):
def do_GET(self):
if self.path == '/sanitycheck':
self.send_response(200)
self.send_header('Content-type', 'application/json')
self.end_headers()
self.wfile.write("{ 'text': 'You are sane.' }")
else:
self.wfile.write(self.path)
def kill_server(httpd):
open("/tmp/log", "w").write("KILLING")
httpd.shutdown()
def start_simple_server(port):
httpd = SocketServer.TCPServer(("", port), RestHTTPRequestHandler)
atexit.register(kill_server, httpd)
httpd.serve_forever()
return httpd
在/tmp/log中什么都没有写,这让我觉得 atexit
可能没有被调用。
这是我如何实例化服务器的:
p = Process(target=start_simple_server, args=(port,))
p.start()
然后当我完成时,要终止它,我只需调用:
p.terminate()
这确实会杀掉进程,并且根据我的理解应该会触发 atexit
的调用——但它没有 :(
有什么想法吗?
2 个回答
0
我最终采取了一种稍微不同的方法,这个方法受到了David Beazley的一些代码的启发... 这是服务器的代码:
from BaseHTTPServer import BaseHTTPRequestHandler
import SocketServer
import multiprocessing
import cgi
import urlparse
class StoppableHTTPServerProcess(multiprocessing.Process):
def __init__(self, address, handler):
multiprocessing.Process.__init__(self)
self.exit = multiprocessing.Event()
self.server = StoppableHTTPServer(address, handler)
def run(self):
while not self.exit.is_set():
self.server.handle_request()
def shutdown(self):
self.exit.set()
class RestHTTPRequestHandler(BaseHTTPRequestHandler):
def do_GET(self):
self.wfile.write(self.path)
class StoppableHTTPServer(SocketServer.TCPServer):
allow_reuse_address = True
timeout = 0.5
def start_simple_server(port):
process = StoppableHTTPServerProcess(("", port), RestHTTPRequestHandler)
return process
这是调用代码:
p = start_simple_server(port)
p.start()
当我完成的时候...
p.shutdown()
1
在Python中,atexit模块的功能是当程序正常结束时,自动执行一些清理工作,比如关闭文件或释放资源。但是,如果你强行终止一个进程,比如使用任务管理器结束它,atexit就不会执行了。这意味着你可能会错过一些重要的清理步骤。
>>>import atexit
>>> def hook():
... print "hook ran"
...
>>> atexit.register(hook)
<function hook at 0x100414aa0>
>>>
# in another terminal: kill <python process id>
>>> Terminated