Добавление поведения 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 вызов. Но если у вас просто есть ряд компонентов, которые в основном независимы друг от друга, это шаблон, который я бы использовал *.

*. С другой стороны, если они должны быть изолированы друг от друга, я бы использовал шаблон диспетчера приложений, рекомендованный в документах.