【问题标题】:Modify CherryPy's shutdown procedure修改 CherryPy 的关机程序
【发布时间】:2017-02-01 04:23:28
【问题描述】:

所以我有一个封装状态机的cherry py 服务器。在幕后,这个状态机完成了管理进程、线程和缓存的所有繁重工作,而且它是线程安全的。因此,在启动我的樱桃 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,它适用于例如烧瓶开发服务器。

但是,cherrypy 吞下 KeyBoard 中断并等待其子线程关闭,因为它们包含对 app.state_machine 的引用,它们将无限期地死锁,直到调用 app.state_machine.shutdown()。

那么如何修改cherrypy的关闭程序,让它正确调用shutdown呢?

【问题讨论】:

  • 我认为,您可以实现a CherryPy plugin 来执行状态机启动和关闭,绑定到 CherryPy 应用程序周期。

标签: python multithreading webserver cherrypy


【解决方案1】:

根据 web ninja 的建议,答案是使用插件。

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

【讨论】:

  • 我认为,在这种情况下,您不需要在 finally 块中关闭。另外,也许你会在插件初始化程序中直接启动它。
  • 多次调用shutdown没有任何作用,这可以保护我免受cherrypy引擎抛出的错误,但我不知道它们是否真的存在.....
  • 您应该将与状态机相关的所有内容都保存在插件中,以使其解耦。 cherrypy.engine.block() 将捕获 KeyboardInterrupt(它也会捕获 SystemExit,但随后会重新引发它),以相反的顺序取消订阅插件并将关闭服务器。无论如何,这样你就可以.unsubscribe()你的插件(这将触发.stop()被调用),而无需从主模块中与状态机API接口。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-12-20
  • 2011-05-20
  • 1970-01-01
  • 2010-09-24
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多