So I have a cherry py server which wraps a state machine. Behind the scenes this state machine does all the heavy lifting of mananging processes and threads and caching, and it is thread safe. So on start up of my cherry py I attach it to the app and the requests call into app.state_machine.methods.
In pseudo code I do:
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()
The intent here is that a key board interrupt should propagate out the app and calls state_machine.shutdown, which works with, e.g. the flask development server.
However, cherrypy swallows the KeyBoard interrupt and waits for its child threads to shutdown, since they contain references to app.state_machine, they will deadlock indefinitely until app.state_machine.shutdown() is called.
So how can I modify the shutdown procedure of cherrypy such that it will call shut down correctly?
As suggested by web ninja, the answer was to use the plugin.
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")
Then just do :
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()