我正在处理一个python应用程序,它由多个分布式轻量级组件组成,使用它们进行通信 的RabbitMQ & 海带。
组件侦听两个队列,并且可以在每个队列上接收多个消息类型。子类可以通过注册自定义处理程序来覆盖每种消息类型的处理方式。
这一切都很好。
我现在要求每个组件必须具有基本的REST / HTML接口。您的想法是将浏览器指向正在运行的组件,并获取有关当前正在执行的操作的实时信息(处理的消息,CPU使用情况,状态信息,日志等)
它需要是轻量级的,所以经过一些研究我已经确定了Flask(但我愿意接受建议)。在伪代码中,这意味着:
class Component:
Queue A
Queue B
...
def setup(..):
# connect to the broker & other initialization
def start(..):
# start the event loop and wait for work
def handle_msg_on_A(self,msg):
# dispatch a msg to a handler depending on the msg type
def handle_msg_on_B(self,msg):
...
...
并添加了许多视图方法:
@app.route('/')
def web_ui(self):
# render to a template
@app.route('/state')
def get_state(self):
# REST method to return some internal state info as JSON
...
但是,将Web UI固定到类似这样的类上会中断 固体 原则并带来继承问题(子类可能希望显示更多/更少的信息)。装饰器不是继承的,因此需要显式覆盖和重新装饰每个视图方法。也许使用mixin +反射可以以某种方式工作,但它感觉hackish。
相反,使用组合可以工作:将Web内容放在一个单独的类中,该类将url路由委托给嵌套组件上的一组固定的预定义多态方法。
这样,组件仍然没有意识到Flask,但代价是一些灵活性损失(可用方法的集合是固定的)。
我现在发现了 烧瓶蓝图 和 应用程序调度 看起来他们可以带来更好,更具扩展性的解决方案。但是,我还没有绕过它们。
我觉得我在这里错过了一个设计模式,并希望有更多烧瓶或有这类问题经验的人可以发表评论。
在Flask 0.7中悄悄地引入了一些可能对你感兴趣的东西 - 可插拔视图。这些是 基于班级 而不是基于功能的端点 - 所以你可以使用 dispatch_request
管理状态转换的方法(仅在需要时覆盖它)。
与使用应用程序调度相反,这样做的好处就是获得 url_for
支持所有应用程序(而不是在跨越应用程序边界的URL中使用硬编码。)您必须确定这是否可能是您的应用程序的问题。
在伪代码中:
# File: Components.py
from flask.views import View
class Component(View):
# Define your Component-specific application logic here
dispatch_request(self, *url_args, **url_kwargs):
# Define route-specific logic that all Components should have here.
# Call Component-specific methods as necessary
class Tool_1(Component):
pass
class Tool_2(Component):
# Override methods here
# File: app.py
from flask import Flask
from yourapplication import Tool_1, Tool_2
app = Flask()
# Assuming you want to pass all additional parameters as one argument
app.add_url_rule("/tool_1/<path:options>", "tool1", view_func=Tool_1.as_view())
# Assuming you want to pass additional parameters separately
tool_2_view = Tool_2.as_view()
app.add_url_rule("/tool_2/", "tool2", view_func=tool_2_view )
app.add_url_rule("/tool_2/<option>", "tool2", view_func=tool_2_view)
app.add_url_rule("/tool_2/<option>/<filter>", "tool2", view_func=tool_2_view)
您 能够 如果您有一系列逻辑上连接在一起的组件,并且您不想记住放置,请在混合中添加蓝图 /prefix
在每个人的面前 add_url_rule
呼叫。但是如果你只有一系列的组件 大多 彼此独立,这是我使用的模式*。
*。 另一方面,如果他们需要 孤立 我将使用文档中推荐的Application Dispatch模式。
在Flask 0.7中悄悄地引入了一些可能对你感兴趣的东西 - 可插拔视图。这些是 基于班级 而不是基于功能的端点 - 所以你可以使用 dispatch_request
管理状态转换的方法(仅在需要时覆盖它)。
与使用应用程序调度相反,这样做的好处就是获得 url_for
支持所有应用程序(而不是在跨越应用程序边界的URL中使用硬编码。)您必须确定这是否可能是您的应用程序的问题。
在伪代码中:
# File: Components.py
from flask.views import View
class Component(View):
# Define your Component-specific application logic here
dispatch_request(self, *url_args, **url_kwargs):
# Define route-specific logic that all Components should have here.
# Call Component-specific methods as necessary
class Tool_1(Component):
pass
class Tool_2(Component):
# Override methods here
# File: app.py
from flask import Flask
from yourapplication import Tool_1, Tool_2
app = Flask()
# Assuming you want to pass all additional parameters as one argument
app.add_url_rule("/tool_1/<path:options>", "tool1", view_func=Tool_1.as_view())
# Assuming you want to pass additional parameters separately
tool_2_view = Tool_2.as_view()
app.add_url_rule("/tool_2/", "tool2", view_func=tool_2_view )
app.add_url_rule("/tool_2/<option>", "tool2", view_func=tool_2_view)
app.add_url_rule("/tool_2/<option>/<filter>", "tool2", view_func=tool_2_view)
您 能够 如果您有一系列逻辑上连接在一起的组件,并且您不想记住放置,请在混合中添加蓝图 /prefix
在每个人的面前 add_url_rule
呼叫。但是如果你只有一系列的组件 大多 彼此独立,这是我使用的模式*。
*。 另一方面,如果他们需要 孤立 我将使用文档中推荐的Application Dispatch模式。