修改 CherryPy 的关机程序
Modify CherryPy's shutdown procedure
所以我有一个包装状态机的 cherry py 服务器。在幕后,这个状态机完成了管理进程和线程以及缓存的所有繁重工作,而且它是线程安全的。所以在启动我的 cherry py 时,我将它附加到应用程序并且请求调用 app.state_machine.methods.
在伪代码中我这样做:
from flask_app import app
import cherrypy
#configure app
app.state_machine = State_Machine.start()
try:
cherrypy.tree.graft(app, "/")
cherrypy.server.unsubscribe()
server = cherrypy._cpserver.Server()
server.socket_host="0.0.0.0"
server.socket_port = 5001
server.thread_pool = 10
server.subscribe()
cherrypy.engine.start()
cherrypy.engine.block()
except KeyboardInterrupt:
logging.getLogger(__name__).warn("Recieved keyboard interrupt")
except Exception:
logging.getLogger(__name__).exception("Unknown exception from app")
finally:
logging.getLogger(__name__).info("Entering Finally Block")
state_machine.shutdown()
这里的目的是键盘中断应该传播到应用程序并调用 state_machine.shutdown,它适用于,例如Flask 开发服务器。
然而,cherrypy 吞下 KeyBoard 中断并等待其子线程关闭,因为它们包含对 app.state_machine 的引用,它们将无限期地死锁,直到调用 app.state_machine.shutdown()。
那么如何修改cherrypy的关机程序使其正确调用关机呢?
按照网络忍者的建议,答案是使用插件。
from cherrypy.process import wspbus, plugins
class StateMachinePlugin(plugins.SimplePlugin) :
def __init__(self, bus, state_machine):
plugins.SimplePlugin.__init__(self, bus)
self.state_manager = state_machine
def start(self):
self.bus.log("Starting state_machine")
self.state_machine.run()
def stop(self):
self.bus.log("Shutting down state_machine")
self.state_machine.shutdown()
self.bus.log("Successfully shut down state_machine")
然后就这样做:
from flask_app import app
import cherrypy
#configure app
app.state_machine = State_Machine.start()
try:
cherrypy.tree.graft(app, "/")
cherrypy.server.unsubscribe()
server = cherrypy._cpserver.Server()
server.socket_host="0.0.0.0"
server.socket_port = 5001
server.thread_pool = 10
server.subscribe()
###########################Added This line####################
StateMachinePlugin(cherrypy.engine, app.state_machine).subscribe()
#####################End Additions##########################
cherrypy.engine.start()
cherrypy.engine.block()
except KeyboardInterrupt:
logging.getLogger(__name__).warn("Recieved keyboard interrupt")
except Exception:
logging.getLogger(__name__).exception("Unknown exception from app")
finally:
logging.getLogger(__name__).info("Entering Finally Block")
state_machine.shutdown()
所以我有一个包装状态机的 cherry py 服务器。在幕后,这个状态机完成了管理进程和线程以及缓存的所有繁重工作,而且它是线程安全的。所以在启动我的 cherry py 时,我将它附加到应用程序并且请求调用 app.state_machine.methods.
在伪代码中我这样做:
from flask_app import app
import cherrypy
#configure app
app.state_machine = State_Machine.start()
try:
cherrypy.tree.graft(app, "/")
cherrypy.server.unsubscribe()
server = cherrypy._cpserver.Server()
server.socket_host="0.0.0.0"
server.socket_port = 5001
server.thread_pool = 10
server.subscribe()
cherrypy.engine.start()
cherrypy.engine.block()
except KeyboardInterrupt:
logging.getLogger(__name__).warn("Recieved keyboard interrupt")
except Exception:
logging.getLogger(__name__).exception("Unknown exception from app")
finally:
logging.getLogger(__name__).info("Entering Finally Block")
state_machine.shutdown()
这里的目的是键盘中断应该传播到应用程序并调用 state_machine.shutdown,它适用于,例如Flask 开发服务器。
然而,cherrypy 吞下 KeyBoard 中断并等待其子线程关闭,因为它们包含对 app.state_machine 的引用,它们将无限期地死锁,直到调用 app.state_machine.shutdown()。
那么如何修改cherrypy的关机程序使其正确调用关机呢?
按照网络忍者的建议,答案是使用插件。
from cherrypy.process import wspbus, plugins
class StateMachinePlugin(plugins.SimplePlugin) :
def __init__(self, bus, state_machine):
plugins.SimplePlugin.__init__(self, bus)
self.state_manager = state_machine
def start(self):
self.bus.log("Starting state_machine")
self.state_machine.run()
def stop(self):
self.bus.log("Shutting down state_machine")
self.state_machine.shutdown()
self.bus.log("Successfully shut down state_machine")
然后就这样做:
from flask_app import app
import cherrypy
#configure app
app.state_machine = State_Machine.start()
try:
cherrypy.tree.graft(app, "/")
cherrypy.server.unsubscribe()
server = cherrypy._cpserver.Server()
server.socket_host="0.0.0.0"
server.socket_port = 5001
server.thread_pool = 10
server.subscribe()
###########################Added This line####################
StateMachinePlugin(cherrypy.engine, app.state_machine).subscribe()
#####################End Additions##########################
cherrypy.engine.start()
cherrypy.engine.block()
except KeyboardInterrupt:
logging.getLogger(__name__).warn("Recieved keyboard interrupt")
except Exception:
logging.getLogger(__name__).exception("Unknown exception from app")
finally:
logging.getLogger(__name__).info("Entering Finally Block")
state_machine.shutdown()