2014-09-16 12 views
9

Próbuję utworzyć zadanie asynchroniczne, które nie zablokuje żądania. Użytkownik wprowadza żądanie, zadanie zostanie uruchomione, a kontroler wyświetli komunikat "Zadanie jest uruchomione ...", aby uniknąć zablokowania żądania oczekującego na zakończenie zadania. Gdy zadaniem jest wykończenie, będzie wykonać onComplete i zrobić coś z wynikiem tego zadania (na przykład wywołać usługę, która wyśle ​​wiadomość do użytkownika)Błąd zadania asynchronicznego

| Error 2014-09-16 17:38:56,721 [Actor Thread 3] ERROR gpars.LoggingPoolFactory - Async execution error: null 

Kod jest następujący:

package testasync 

import static grails.async.Promises.* 

class TestController { 

    def index() { 
    //Create the job 
    def job1 = task { 
     println 'Waiting 10 seconds' 
     Thread.sleep(10000) 
     return 'Im done' 
    } 
    //On error 
    job1.onError { Throwable err -> 
     println "An error occured ${err.message}" 
    } 
    //On success 
    job1.onComplete { result -> 
     println "Promise returned $result" 
    } 
    render 'Job is running...' 
    } 

Kompletna StackTrace:

| Error 2014-09-17 10:35:24,522 [Actor Thread 3] ERROR gpars.LoggingPoolFactory - Async execution error: null 
Message: null 
    Line | Method 
->> 72 | doCall in org.grails.async.factory.gpars.GparsPromise$_onError_closure2 
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
    |  62 | run  in groovyx.gpars.dataflow.DataCallback$1 
    | 1145 | runWorker in java.util.concurrent.ThreadPoolExecutor 
    | 615 | run  in java.util.concurrent.ThreadPoolExecutor$Worker 
^ 745 | run . . . in java.lang.Thread 
+0

istnieje kompletny ślad? – cfrick

+0

dodał kompletny stacktrace – agusluc

Odpowiedz

0

Podczas tworzenia zadania obietnicę aSYNC wewnątrz kontrolerze trzeba rzeczywiście zwróci odpowiedź wywołując get() metoda w zadaniu lub metody nigdy nie zostaną wywołane. Dodawanie:

job1.get() 

Zanim zadzwonisz pod numer render, rozwiążesz problem.

+2

Ale get() blokuje bieżące żądanie, więc renderowanie nie jest wykonywane, dopóki zadanie asynchroniczne nie zostanie zakończone. Chcę uruchomić zadanie, zakończyć żądanie (aby uniknąć czasu oczekiwania na końcu użytkownika), a gdy zadanie się zakończy, wybierz wynik z jednostką onComplete. – agusluc

+0

@agusluc Masz jakieś rozwiązanie tego problemu? Mam taki sam problem z grailsami 2.4.4 –

+0

@ShashankAgrawal i dodałem odpowiedź z znalezionym rozwiązaniem. Mam nadzieję, że pomaga – agusluc

1

Udało mi się pozbyć tego wyjątku w kontrolerze, usuwając wywołania onComplete i onError. Domyślam się, że wyjątek ma miejsce, ponieważ wątek nadrzędny zakończył się po wywołaniu render.

więc:

Promise p = task { 
    complexAsyncMethodCall(); // (1) do stuff 
} 
.onComplete { result -> println result } // (2) on success 
.onError { Throwable t -> System.err.println("Error: " + t) } // (3) on error 

Staje:

Promise p = task { 
    try { 
     def result = complexAsyncMethodCall(); // (1) do stuff 
     println result // (2) on success 
    } catch(Throwable t) { 
     System.err.println("Error: " + t) // (3) on error 
    } 
} 

Dodaje to sprzężenie pomiędzy swojej pracy (1) oraz przetwarzania wyników (2 i 3), ale można przezwyciężyć przez pisanie własne opakowanie Closure, które przyjmuje dodatkowe zamknięcia jako argumenty. Coś takiego:

// may not work! written off the top of my head 
class ProcessableClosure<V> extends Closure<V> { 
    Closure<V> work; 
    Closure<?> onError; 
    Closure<?> onComplete; 

    @Override 
    public V call(Object... args) { 
     try { 
      def result = work.call(args); // (1) do stuff 
      onComplete.call(result); // (2) on complete 
     } catch(Exception e) { 
      onError.call(result); // (3) on error 
     } 
    } 
} 

To sprawia, że ​​kod jest bardziej czytelny:

Closure doWork = { complexAsyncMethodCall(); } // (1) do stuff 
Closure printResult = { println it } // (2) on complete 
Closure logError = { Throwable t -> log.error t } // (3) on error 
Closure runEverythingNicely = new ProcessableClosure(work: doWork, onComplete: printResult, onError: logError) 
Promise p = task { runEverythingNicely }