Добавление поведения REST в класс с флягой, для чертежей?
Я имею дело с приложением python, которое состоит из нескольких распределенных легких компонентов, которые обмениваются данными с помощью RabbitMQ и Kombu.
Компонент прослушивает две очереди и может принимать несколько типов сообщений в каждой очереди. Подклассы могут переопределять способ обработки каждого типа сообщений путем регистрации пользовательских обработчиков.
Все это прекрасно работает.
Теперь у меня есть дополнительное требование: каждый компонент должен иметь базовый интерфейс REST/HTML. Идея заключается в том, что вы указываете свой браузер на работающем компоненте и получаете информацию в реальном времени о том, что он сейчас делает (какие сообщения обрабатываются, использование процессора, информация о состоянии, журнал и т.д.).
Он должен быть легким, поэтому после некоторых исследований я остановился на 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
...
Однако прикрепление веб-интерфейса к классу, как это, нарушает принципы SOLID и создает проблемы с наследованием (подкласс может отображать больше/меньше информации). Декораторы не наследуются, поэтому каждый метод просмотра должен быть явно переопределен и исправлен. Возможно, использование mixin + reflection могло бы как-то работать, но оно кажется хакерским.
Вместо этого можно было бы использовать композицию: поместите веб-материал в отдельный класс, который делегирует URL-маршруты фиксированному предопределенному набору полиморфных методов для вложенного компонента.
Таким образом, компоненты не знают о Flask за счет некоторой потери гибкости (набор доступных методов фиксирован).
Теперь я обнаружил Флаги чертежей и Диспетчер приложений и похоже, что они могут принести лучшее, более расширяемое решение. Тем не менее, мне еще предстоит обвести вокруг себя голову.
Я чувствую, что у меня отсутствует шаблон дизайна здесь, и, надеюсь, кто-то с большим количеством флэшек или опыта с этим типом проблем может комментировать.
Ответы
Ответ 1
Что-то еще было тихо введено в Flask 0.7, которое может вас заинтересовать - Pluggable Views. Это конечные точки, основанные на классах, а не на основе функций, поэтому вы можете использовать метод 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
вызов. Но если у вас просто есть ряд компонентов, которые в основном независимы друг от друга, это шаблон, который я бы использовал *.
*. С другой стороны, если они должны быть изолированы друг от друга, я бы использовал шаблон диспетчера приложений, рекомендованный в документах.