Przetwarzanie zadań za pośrednictwem aplikacji internetowej: aktualizacje statusu w czasie rzeczywistym i wiadomości zaplecza

Chciałbym zaimplementować (open source) aplikację internetową, w której użytkownik wysyła jakieś żądanie za pośrednictwem swojej przeglądarki do aplikacji internetowej Pythona. Dane żądania są używane do zdefiniowania i przesłania pewnego rodzaju ciężkiego zadania obliczeniowego. Zadania obliczeniowe są zlecane na zewnątrz "worker backend" (również Python). Podczas przetwarzania zadania zadanie przechodzi przez różne etapy w czasie(od" przedłożone "przez Stany pośrednie do" ukończone", najlepiej). To, co chciałbym osiągnąć, to pokazać bieżący stan zadania dla użytkownika w czasie rzeczywistym. Oznacza to, że backend worker musi komunikować Stany zadań z powrotem do aplikacji internetowej. Następnie aplikacja webowa musi przesyłać informacje do przeglądarki użytkownika. Przyniosłem ci zdjęcie, które schematycznie opisuje podstawową ideę: schematyczny opis problemu

Liczby w czerwonych kółkach wskazują chronologiczny porządek wydarzeń. "web app" i "worker backend" są nadal do zaprojektowania. Byłbym wdzięczny, gdybyś mógł mi pomóc z jakąś technologią. decyzje.

Moje pytania, konkretnie:

  1. Jaką technologię przesyłania wiadomości powinienem zastosować między aplikacją internetową a zapleczem worker? Gdy backend worker emituje sygnał (jakiś komunikat) o określonym zadaniu, musi wywołać jakieś zdarzenie w aplikacji internetowej. W związku z tym, potrzebuję pewnego rodzaju callback, który jest związany z klientem, który początkowo poprosił o złożenie zadania. Myślę, że potrzebuję jakiegoś mechanizmu pub/sub, gdzie backend worker publikuje i aplikacja internetowa subskrybuje. Gdy aplikacja internetowa otrzyma wiadomość, reaguje na nią, wysyłając aktualizację statusu do klienta. Chcę, aby backend workera był skalowalny i silnie oddzielony od aplikacji internetowej. Dlatego myślałem o użyciu Redis lub ZeroMQ do tego zadania. Co o tym myślisz? Czy moje podejście jest zbyt skomplikowane?

  2. Jakiej technologii należy użyć do przesyłania informacji do przeglądarki? Po prostu z perfekcjonizmu chciałbym mieć w czasie rzeczywistym aktualizacje. Nie chcę sondować z dużą częstotliwością. Chcę natychmiastowego push do klienta, gdy backend worker emituje wiadomość :-). Nie potrzebuję również maksymalnej obsługi przeglądarki. Ten projekt przede wszystkim jest mniej więcej techdemo dla mnie. Czy powinienem wybrać HTML5 server-sent events / websockets? A może poleciłbyś coś innego?

Wielkie dzięki za rekomendacje z góry.

Author: Jan-Philip Gehrcke, 2012-10-04

3 answers

Aby być użytecznym, Twoja aplikacja internetowa będzie miała bazę danych. Chciałbym utworzyć tabelę w tej bazie danych, która jest specjalnie dla tych zadań. Dla każdej pracy miałbyś "Stan".

Upraszcza to Twój system, ponieważ możesz po prostu wysłać prośbę o rozpoczęcie pracy i przekazać ją pracownikom zaplecza (zmq jest dobrym rozwiązaniem dla tej IMO). Ponieważ używasz Pythona do back-endu, bardzo trywialne jest, aby Twoje zadania worker zaktualizowały swoje obecne zadanie robocze w bazy danych lub innego 'updater', którego jedynym zadaniem jest aktualizacja pól w bazie danych (oddzielenie logiki będzie lepszym rozwiązaniem, pozwala na uruchomienie wielu 'updater', jeśli robisz dużo aktualizacji)

Wtedy dla Twojego frontendu, ponieważ nie chcesz przepytywać serwera, zrobiłbym coś w rodzaju 'long poll'. To co w zasadzie robisz to sprawdzanie serwera, ale serwer faktycznie "odpowiada", dopóki nie nastąpi zmiana danych, które jesteś zainteresowany. Gdy tylko nastąpi zmiana, odpowiadasz z prośbą. Na frontendzie masz JS ponownie nawiązać połączenie, gdy tylko otrzyma najnowszą aktualizację. To rozwiązanie jest zgodne między przeglądarkami, o ile używasz frameworka JS, który jest również między przeglądarkami (sugerowałbym jQuery).


Aby wyeliminować badanie bazy danych aplikacji internetowych, wykonaj następujące czynności:

Aby wstępne żądanie było długim zapytaniem do aplikacji internetowej, aplikacja internetowa wysyła wiadomość zmq do Twój backend (prawdopodobnie musiałby być zrobiony z gniazdem REQ/REP) i czeka. Czeka, aż otrzyma wiadomość z backendu zmq ze zmianą stanu. Kiedy otrzymuje zmianę stanu, reaguje na frontend zmianą. W tym momencie frontend wyśle nowe żądanie long-poll (z tym jobs current id, który może być jego tożsamością), a aplikacja internetowa ponownie połączy się z backendem i czeka na kolejną zmianę stanu. Sztuczka, aby to zadziałało, to użycie ZMQ ' s ZMQ_IDENTITY na socket, kiedy został pierwotnie utworzony (w pierwszym żądaniu). Pozwoli to aplikacji internetowej Na ponowne połączenie się z tym samym gniazdem backendu i uzyskanie nowych aktualizacji. Gdy backend ma nową aktualizację do wysłania, zasygnalizuje aplikację internetową, która z kolei odpowie na żądanie long-poll ze zmianą stanu. W ten sposób nie ma polling, żadnej bazy danych zaplecza i wszystko jest sterowane zdarzeniami przez pracowników zaplecza.

Ustawiłbym jakiś watch-dog, który jeśli frontend zniknie (przełącza strony lub zamyka przeglądarkę), gniazda backendowe zostaną prawidłowo zamknięte. Nie muszą siedzieć bezczynnie blokując, gdy zmieni się stan.

 3
Author: g19fanatic,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-10-05 14:14:08

Opcją byłoby użycie WebSocket. Jeśli pójdziesz tą drogą, możesz sprawdzić Autobahn , która zawiera klientów i serwery dla Pythona (Twisted), a także protokół RPC+PubSub na szczycie WebSocket (z libs dla Pythona, JavaScript i Android). Korzystanie z subskrypcji RPC + PubSub zabezpiecza znaczącą pracę i może pasować do Twoich potrzeb (zgłoszenie zadania => RPC, aktualizacje pracy zadania => PubSub).

AutobahnPython działa na skręconym, który może dodatkowo działać jako pojemnik WSGI, który sprawia, że możliwość uruchomienia Flask (lub innego frameworka www opartego na WSGI). Wszystko można uruchomić na 1 porcie / serwerze. Istnieje przykład repozytorium GitHub Autobahn dla tego ostatniego.

Disclaimer: jestem autorką Autobahn i WAMP i pracuję dla Tavendo.

Szczegóły: Zakładam, że Twoi pracownicy robią intensywne CPU i / lub blokują rzeczy.

Po pierwsze, czy Twoi pracownicy są czystymi Pythonami czy zewnętrznymi programami?

Jeśli to drugie, możesz użyć Twisted process protocol instancje, które komunikują się za pomocą rur stdio (w sposób nieblokujący) z głównego skręconego wątku. Jeśli pierwszy, możesz użyć puli wątków tła Twisted i użyć Twisted deferToThread (zobacz: http://twistedmatrix.com/documents/current/core/howto/threading.html).

Autobahn działa na głównym skręconym wątku reaktora. Jeśli twój worker również to robi( patrz komentarze wcześniej), możesz bezpośrednio wywoływać metody w instancjach WebSocket/WAMP factory/protocol. Jeśli nie (worker działa na wątek tła), należy wywołać te metody poprzez callFromThread.

Jeśli używasz WAMP, najważniejsze jest uzyskanie referencji dla WampServerFactory dla każdego pracownika. Pracownik może następnie wysłać Zdarzenie PubSub do wszystkich subskrybentów, wywołując odpowiednią metodę fabryczną.

 4
Author: oberstet,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-10-05 14:30:54

Ponieważ mówisz o aplikacji internetowej Pythona, polecam zajrzeć do:

Jaką technologię przesyłania wiadomości powinienem zastosować między aplikacją internetową a zapleczem worker?

Selery - Podziel swoje zadania na mniejsze zadania, które zwracają wyniki, które muszą być pokazane klientowi

Jakiej technologii należy użyć do przesyłania informacji do przeglądarki?

Albo Socket IO na NodeJS rodzaj serwera po stronie js framework lub web socket library for you python web framework

Jeśli nie jesteś zbyt przywiązany do Pythona, sprawdź Meteor

W oparciu o ten wątek , inne sposoby aktualizacji postępu z serwera do klienta WWW w czasie rzeczywistym mogą obejmować zapisanie statusu postępu do bazy danych redis lub użycie Oribited/ Morbid (oba oparte na Twisted ) przy użyciu protokołu STOMP opartego na asynchronicznych wynikach z selery ' s podzadania

 3
Author: Pratik Mandrekar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-10-05 14:59:54