2011-08-31 9 views
11

Mam do czynienia z aplikacją python, która składa się z wielu rozproszonych lekkich komponentów, które komunikują się przy użyciu RabbitMQ & Kombu.Dodawanie zachowania REST do klasy z kolbą, case dla planów?

Komponent słucha w dwóch kolejkach i może odbierać wiele typów wiadomości w każdej kolejce. Podklasy mogą nadpisać sposób przetwarzania każdego typu wiadomości poprzez rejestrowanie niestandardowych procedur obsługi. Wszystko to działa dobrze.

Mam teraz dodatkowe wymaganie, że każdy komponent musi mieć podstawowy interfejs REST/HTML. Pomysł polegający na tym, że kierujesz przeglądarkę do działającego komponentu i uzyskujesz w czasie rzeczywistym informacje o tym, co aktualnie robi (jakie wiadomości przetwarza, użycie procesora, informacje o stanie, dziennik itp.).

To musi być lekkie, więc po pewnych badaniach zdecydowałem się na Flask (ale jestem otwarty na sugestie). W Pseudokod oznacza to przyjmuje:

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): 
    ... 

    ... 

i dodając kilka widzenia metod:

@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 

    ... 

Jednak przykręcenie UI internetową na klasy jak ten łamie SOLID zasad i przynosi problemy z dziedziczenia (podklasę może chcieć wyświetlić więcej/mniej informacji). Dekoratory nie są dziedziczone, więc każda metoda widoku musiałaby zostać jawnie nadpisana i zmieniona. Może użycie mixin + reflection może jakoś zadziałać, ale czuje się hackish.

Zamiast tego, użycie kompozycji może działać: umieść elementy sieciowe w osobnej klasie, która deleguje trasy adresów URL do ustalonego, predefiniowanego zestawu metod polimorficznych w komponencie zagnieżdżonym. W ten sposób komponenty pozostają nieświadome Flasku kosztem utraty elastyczności (zestaw dostępnych metod jest stały).

Właśnie odkryłem Flask blueprints i Application Dispatching i wygląda na to, że mogą przynieść lepsze, bardziej rozszerzalne rozwiązanie. Jednak muszę jeszcze owinąć się wokół nich.

Mam wrażenie, że brakuje mi tutaj wzoru i mam nadzieję, że ktoś z większą ilością flak-fu lub doświadczeniem z tego typu problemami może komentować.

Odpowiedz

11

Coś innego zostało po cichu wprowadzone w Kolbie 0.7, które może Cię zainteresować - Pluggable Views. Są to oparte na klasie klasy, a nie na punktach końcowych opartych na funkcjach - możesz więc użyć metody dispatch_request do zarządzania swoimi przejściami między stanami (tylko przesłonięcie w razie potrzeby).

Zaletą tego sposobu, w przeciwieństwie do używania Dispatching aplikacji, jest to, że uzyskujesz url_for wsparcie dla całej aplikacji (w przeciwieństwie do twardego kodu w adresach URL przekraczających granice aplikacji). Będziesz musiał zdecyduj, czy jest to coś, co może być problemem dla Twojej aplikacji.

W pseudo-kod:

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

Ty może plany dodać do mieszanki, jeśli masz szereg elementów, które są połączone ze sobą logicznie i nie chcesz trzeba pamiętać, aby umieścić /prefix przed każdą rozmową add_url_rule. Ale jeśli masz tylko szereg komponentów, które są głównie niezależne od siebie, jest to wzór, którego użyłbym *.

*. Z drugiej strony, jeśli muszą być od siebie izolowane, używałbym wzoru Dispatch aplikacji zalecanego w dokumentach.

+0

Fajnie, dziękuję za odpowiedź, zdecydowanie się na to przyjrzę i zatwierdzę odpowiedź, jeśli się uda – dgorissen

+0

Czy to działa @dgorissen –

Powiązane problemy