2012-07-12 9 views
5

Jak uzyskać dostęp do wyniku zadania z selera w moim głównym procesie aplikacji Django? Lub, jak mogę opublikować do istniejącego połączenia gniazda z oddzielnego procesu?django-socketio z selerem: wysłać do gniazda po wykonaniu zadania async w oddzielnym procesie

Mam aplikację, w której użytkownicy otrzymują wyniki. Po zapisaniu wyniku obliczenia są dokonywane (postępy w osiąganiu celów itd.), A na podstawie tych obliczeń powiadomienia są wysyłane do zainteresowanych użytkowników. Obliczenia mogą zająć 30s +, więc aby uniknąć powolnego interfejsu użytkownika, te operacje są wykonywane w procesie w tle za pomocą zadania Celery, wywoływanego przez sygnał post_save mojego modelu Score.

Idealnie sygnał post_save w moim modelu Nofication mógłby opublikować wiadomość do subskrybowanych klientów (używam django-socketio, opakowania dla gevent-socketio). To wydaje się proste ...

  1. Tworzenie wynik
  2. Czy jakieś obliczenia na nowej instancji Score w procesie tle
  3. Na podstawie tych obliczeń, utwórz Notification
  4. po powiadomieniu uratować, chwycić instancja i publikują do klientów subskrybowanych poprzez połączenie gniazda

jednak po wykonaniu następujących czynności nie jestem pewien, że to możliwe:

  • przechodzącej gevent na wystąpienie SocketIOServer sposobu zwrotnego wywoływanego przez zadanie, ale wymaga to trawienie Przekazany obiekt, który nie jest możliwy

  • przechowywania SESSION_ID Gniazdko'S (różny od session_id Django) w memchache i pobieranie tego w procesie zadania Selera.

  • za pomocą Redis pubsub, więc metody wywoływane przez sygnały post_save w modelach utworzonych w procesie w tle mogą po prostu publikować w kanale Redis, ale odsłuchanie kanału czatu w głównym procesie aplikacji (który ma dostęp do połączenia z gniazdem) blokuje resztę aplikacji.

  • Próbowałem również utworzyć nowe wątki dla każdego klienta Redis, które są tworzone dla każdego subskrybenta gniazda. O ile mogę powiedzieć to wymaga tarła nowego gevent.greenlets.Greenlet i gevent nie mogą być wykorzystywane w wielu wątków

Z pewnością jest to rozwiązanie problemu. czego mi brakuje?

+1

Czy możesz pokazać kod?Dostaję wymagania, ale twoja próba wdrożenia nie jest jasna. Jak wyglądają twoje tasks.py i views.py (zakładając, że używasz tej struktury plików)? –

+0

, kiedy uruchamianie programów obsługi języka początkowego na serwerze, co one robią? czy subskrybują kolejkę pub-sub redis? Jeśli tak, to czy korzystasz z monkeypatch'a redis-py gevent? gdzieś w twoim ap musisz umieścić tę linię: 'import redis, gevent; redis.connection.socket = gevent.socket' https://github.com/andymccurdy/redis-py/pull/199. Rzeczą zrozumiałą jest to, że zielone środowisko, takie jak moduły obsługi socketio, nadal blokuje proces, jeśli nie dbasz o to, aby korzystać z zainstalowanych w gevent łatek/nazw plików. – Thomas

Odpowiedz

0

Masz już Django socketio, pisząc pub/sub z REDiS byłoby szkoda :)

po stronie klienta:

var socket = new io.Socket(); 
socket.connect(); 
socket.on('connect', function() { 
    socket.subscribe({{ score_update_channel }}); 
}); 

po stronie serwera:

from django_socketio import broadcast_channel 
def user_score_update(user): 
    return 'score_updates_user_%s' % user.pk 

channel = user_score_update(user) 
broadcast_channel(score_result_data, channel) 

Trzeba uruchomić emisję w procesie django-socketio; jeśli uruchomisz go z innego procesu (pracownik selera), to nie zadziała (kanały odwołują się do pamięci przez proces django-socketio); Możesz rozwiązać ten problem, zawijając go w widoku i że seler wywoła (wykonując prawdziwe żądanie http), gdy zadanie zostanie zakończone.