2017-12-16 86 views
5

W aplikacji django uruchamiam zadania asynchroniczne i chcę pokazać postęp, błędy itp. Dla użytkownika. Jeśli występują błędy, użytkownik powinien przekierować na stronę, na której wymagane jest dodatkowe wprowadzenie lub jakieś działanie w celu rozwiązania problemu. Jaki jest najlepszy sposób komunikowania się z pracy selera z powrotem do przodu?Django pracownik do selera wysyłanie wiadomości w czasie rzeczywistym i komunikaty o wynikach do interfejsu użytkownika

Oto podstawowa struktura w pseudo kod:

# views.py 
from tasks import run_task 

def view_task(): 
    run_task.delay() 
    return render(request, 'template.html') 

# tasks.py 
from compute_module import compute_fct 

@shared_task 
def run_task(): 
    result = compute_fct() 

    # how to catch status update messages from compute_module while compute_fct is running?? 

    if result == 'error': 
     handle_error() 
    else: 
     handle_succes()  

# compute_module 
import pandas as pd 

def compute_fct(): 
    # send message: status = loading file 
    df = pd.read_csv('test.csv') 
    # send message: status = computing 
    val = df['col'].mean() 

    if val is None: 
     return {'status':'error'} 
    else: 
     return {'status':'success','val':val} 

Co bym idealnie chcą:

  • compute_module.py wykorzystuje moduł Pythona natywną rejestratora. Przez oddzielenie obowiązków chcę, aby rejestrowanie było jak najbardziej ogólne i wykorzystywać standardowe rejestratory Pythona/Django. Ale wydaje się, że nie są zaprojektowane do wysyłania wiadomości na front.
  • zadanie seler jakoś radzi sobie dzienniki i zamiast wyświetlania ich na stdout przekierowuje je do popychacza
  • Czołowy js pokazy i obsługuje wiadomości

Nie może być standardowe sposoby komunikowania się pomiędzy pracownikiem selera i przód koniec, że nie jestem świadoma. ten scenariusz musi zdarzać się często i jestem zaskoczony, że jest to trudne do wdrożenia. w pewien sposób należy zaprojektować kolejkę komunikatów rabbitmq lub aws sns. poniżej znajdują się zasoby, na które patrzyłem, ale nie czuję, żeby któryś z nich działał bardzo dobrze, ale może jestem po prostu zdezorientowany.

rejestrowania: wydaje się to być więcej o zalogowaniu po stronie serwera, a nie wysyłanie wiadomości do użytkowników

Seler krzywki wydaje się, że chodzi o zadania monitorowania administratora, a nie o sen ding wiadomości do użytkownika

popychacz lubię, ale nie chcę mieć compute_module.py sobie z tym poradzić. To jest na przykład Wolę nie robić żadnej integracji pusher.com wewnątrz compute_module.py. Że mógłbym przekazać obiekt popychacza, który został już instancja więc moduł może tylko wiadomości Push ale znowu wolałbym go mieć charakter ogólny

+0

jaki byłby postęp lokalizacja raport w Twoim przypadku? uruchamiasz zadanie, jest ono zrobione lub występują błędy. jeśli uruchomiłeś zadanie zdekomponowane jako podzadania, czy możesz użyć pracownika sieci do przekazania ostatecznego wyniku każdego sub-suba do klienta? nie jestem też naprawdę * uczucie * logowanie python jako mechanizm sprzężenia zwrotnego użytkownika - podejrzewam, że uzyskanie * ładny * wynik, esp dla html będzie więcej kłopotów niż to jest warte. –

Odpowiedz

0

Jedynym sposobem, I” ve udało się uzyskać statusy w czasie rzeczywistym, to po prostu umieścić niektóre zapisy SQL/wywołania api w samym zadaniu. Robienie rzeczy z wartością zwracaną zadania jest o wiele łatwiejsze, ponieważ można po prostu napisać niestandardową klasę zadań.

Nie jestem do końca pewien, jak to działa, używając Django, ale powinien wyglądać mniej więcej tak.

class CustomTask(celery.Task): 
    def __call__(self, *args, **kwargs): 
     self.start_time = time.time() 

    def on_success(self, retval, task_id, args, kwargs): 
     do_success_stuff() 

    def on_failure(self, exc, task_id, args, kwargs, einfo): 
     do_failure_stuff() 

@shared_task(base=CustomTask) 
def do_stuff(): 
    return create_widgets() 

Pełną listę można znaleźć tutaj: http://docs.celeryproject.org/en/latest/userguide/tasks.html#handlers

+0

ok, jak te widżety byłyby wyświetlane w interfejsie użytkownika bez odwołań do strony? –

+0

Jestem pewien, że jest gdzieś eleganckie rozwiązanie, ale piszę swoje zadania do tabeli, a następnie aktualizuję kolumnę statusu. Ponieważ masz task_id zaraz po uruchomieniu zadania, możesz po prostu zrobić magię jquery, aby uzyskać nowy status. Może coś takiego jak http://www.giantflyingsaucer.com/blog/?p=4310 – lpiner

0

Ok więc poniżej jest pseudo kod na jak mam rozwiązać go teraz. Zasadniczo używam https://pusher.com/docs/javascript_quick_start i przekazywać po stronie serwera instancjonowany obiekt do compute_module. Jedną wadą jest to, że komunikaty popychacza są ephermeralne, więc będę musiał wykonać dodatkową pracę w LogPusher, aby przechowywać je w db, coś na inny dzień ...

Również w mojej prawdziwej realizacji wyzwalam zadanie przez wywołanie ajax $.post() wywołanie w , ponieważ małe zadania wykonane tak szybko użytkownik nigdy nie zobaczy wiadomości popychacza, ponieważ połączenie nie zostało ustanowione (wracając do tego historycznego problemu z wiadomością).

Kolejna alternatywna trasa które nie wspomniano powyżej jest https://channels.readthedocs.io/en/latest/

# views.py 
from tasks import run_task 

def view_task(): 
    run_task.delay('event') 
    return render(request, 'template.html', 'pusher_event':'event') 


# tasks.py 
import pusher 
from django.conf import settings 
from compute_module import compute_fct 

class LogPusher(object): 
    def __init__(self, event): 
     self.pusher_client = pusher.Pusher(app_id=settings.PUSHER_APP_ID, 
         key=settings.PUSHER_KEY, 
         secret=settings.PUSHER_SECRET, 
         cluster=settings.PUSHER_CLUSTER, ssl=True) 
     self.event = event 

    def send(self, data): 
     self.pusher_client.trigger(settings.PUSHER_CHANNEL, self.event, json.dumps(data)) 

@shared_task 
def run_task(pusher_event): 

    log_pusher = LogPusher(pusher_event) 
    result = compute_fct(log_pusher) 

    # how to catch status update messages from compute_module while compute_fct is running?? 

    if result == 'error': 
      log_pusher.send('status':'error') 
    else: 
      log_pusher.send('status':'success') 


# compute_module.py 
import pandas as pd 

def compute_fct(log_pusher): 
    # send message: status = loading file 
    log_pusher.send('status':'loading file') 
    df = pd.read_csv('test.csv') 
    # send message: status = computing 
    log_pusher.send('status':'computing') 
    val = df['col'].mean() 

    if val is None: 
     return {'status':'error'} 
    else: 
     return {'status':'success','val':val} 


# context_processors.py 
# see https://stackoverflow.com/questions/433162/can-i-access-constants-in-settings-py-from-templates-in-django 
from django.conf import settings 

def pusher(request): 
    return {'PUSHER_KEY': settings.PUSHER_KEY, 'PUSHER_CLUSTER': settings.PUSHER_CLUSTER , 'PUSHER_CHANNEL': settings.PUSHER_CHANNEL } 


# template.html 
<script> 

var pusher = new Pusher("{{PUSHER_KEY}}", { 
    cluster: "{{PUSHER_CLUSTER}}", 
    encrypted: true  
}); 

var channel = pusher.subscribe("{{PUSHER_CHANNEL}}"); 
channel.bind("{{pusher_event}}", function(data) { 
    // process data 
}); 

</script> 
Powiązane problemy