5

Próbuję skonfigurować system TimerTask, aby okresowo usuwać wpisy z magazynu danych Google App Engine. Dlatego skonfigurowałem ServletContextListener z Timer.Objectify i TimerTask: Nie zarejestrowano środowiska API dla tego wątku.

Wewnątrz contextInitialized, Zarejestrowałem moje zajęcia zobiektywizować:

ObjectifyService.register(Person.class); 

Jednak, gdy zadanie faktycznie działa, to twierdzi, że nie środowisko API został ustanowiony:

Exception in thread "Timer-0" java.lang.NullPointerException: No API environment is registered for this thread. 
    at com.google.appengine.api.datastore.DatastoreApiHelper.getCurrentAppId(DatastoreApiHelper.java:80) 
    at com.google.appengine.api.datastore.DatastoreApiHelper.getCurrentAppIdNamespace(DatastoreApiHelper.java:90) 
    at com.google.appengine.api.datastore.Query.<init>(Query.java:214) 
    at com.google.appengine.api.datastore.Query.<init>(Query.java:143) 
    at com.googlecode.objectify.impl.cmd.QueryImpl.<init>(QueryImpl.java:72) 
    at com.googlecode.objectify.impl.cmd.LoadTypeImpl.createQuery(LoadTypeImpl.java:50) 
    at com.googlecode.objectify.impl.cmd.LoadTypeImpl.filter(LoadTypeImpl.java:58) 
    at myApp.MyServletContextListener$MyTask.run(MyServletContextListener.java:58) 
    at java.util.TimerThread.mainLoop(Timer.java:555) 
    at java.util.TimerThread.run(Timer.java:505) 

pomysłów ? Próbowałem zmienić linię, która rejestruje klasę na ObjectifyService.factory().register(Person.class);, ale nie pomagało.

+1

To nie ma nic wspólnego z zobiektywizować; zobaczysz ten sam błąd, jeśli wyślesz zapytanie bezpośrednio do interfejsu API niskiego poziomu z wątku licznika czasu. Sugeruję, abyś uprościł pytanie, możesz uzyskać lepszą odpowiedź. Jestem naprawdę zaskoczony, że Timers pracuje w produkcji GAE (w przeciwieństwie do dev). – stickfigure

+0

@stickfigure Nie jestem pewien, czy działają w produkcji, jeszcze nie próbowałem go przesłać. :) –

Odpowiedz

6

Z documentation of java.util.Timer class:

Odpowiednio do każdego obiektu Timer jest pojedynczy wątek tła.

I peeking to the inner code of the java.util.Timer class, możemy zobaczyć, że w zasadzie wystąpienie nić powołując new Thread().

Tymczasem od App Engine's documentation o wykorzystaniu wątków w swojej piaskownicy Java:

należy użyć jednej z metod na ThreadManager tworzyć wątki. Nie można wywołać nowego wątku() samodzielnie lub użyć domyślnej fabryki nici.

Więc co tu się stało jest przedmiotem Timer instancja swój własny wątek, który następnie wykonuje zapytania zobiektywizować, ale ponieważ wątki instancji poza ThreadManager nie ma odpowiedniego API silnika środowiska App skonfigurować dla nich, to zgłasza wyjątek .

Musisz zmienić kod, aby uniknąć używania klas Timer i TimerTask i zamiast tego użyj podstawowych wątków. Na przykład, zamiast przy użyciu:

import java.util.Timer; 
import java.util.TimerTask; 

... 

Timer timer = new Timer(); 
timer.schedule(new TimerTask() 
{ 
    @Override 
    public void run() 
    { 
     // Objectify query here. 
    } 
}, 5000); 

Można zamiast używać:

import com.google.appengine.api.ThreadManager; 

... 

final long tScheduleDelay = 5000; 
ThreadManager.createThreadForCurrentRequest(new Runnable() 
{ 
    @Override 
    public void run() 
    { 
     try 
     { 
      Thread.sleep(tScheduleDelay); 
     } 
     catch (InterruptedException ex) 
     { 
      // log possible exception 
     } 

     // Objectify query here. 
    } 
}).start(); 
+0

Dzięki! Spróbuję tego. Czytałem tylko o zadaniach crona, czy bardziej sensowne byłoby wypróbowanie tego podejścia? –

+0

@choc: Crony mają w najlepszym razie tylko ziarnistość minutę i wydaje się, że jest trochę przesada w przypadku wymiany TimerTask. TaskQueue [etaMillis lub countdownMillis] (https://developers.google.com/appengine/docs/java/taskqueue/overview-push#The_Rate_of_Task_Execution) może lepiej pasować, ale zależy to od Twojego przypadku użycia. Jeśli opublikujesz swoją szczegółową przypadek użycia TimerTask jako inne pytanie StackOverflow i poprosisz o możliwe rozwiązania w GAE, być może będę w stanie zadzwonić. –

+0

Dzięki! Zadałem nowe pytanie tutaj: http://stackoverflow.com/questions/15985309/periodically-delete-entries-in-objectify –

Powiązane problemy