5

私はTimerTaskをGoogle App EngineのdataStoreから定期的にエントリを削除するように設定しようとしています。だからServletContextListenerTimerに設定しました。タスクが実際に実行されるとき、それはAPIの環境が設定されていないと文句を言い、しかしObjectify and TimerTask:このスレッドにAPI環境が登録されていません

ObjectifyService.register(Person.class); 

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) 

任意のアイデアをcontextInitializedインサイド

は、私は私の客観クラスを登録しています?私はクラスを登録する行をObjectifyService.factory().register(Person.class);に変更しようとしましたが、それは役に立たなかったようです。 documentation of java.util.Timer classから

+1

は、これは客観とは何の関係もありません。タイマースレッドから低レベルのAPIに直接問合せを発行すると、同じエラーが表示されます。私はあなたが質問を簡素化することをお勧めします、あなたはより良い答えを得ることができます。私はTimerが(開発者ではなく)GAEプロダクションで働いていると聞いて実際に驚いています。 – stickfigure

+0

@stickfigureプロダクションで働いているのか、まだアップロードしようとしていないのか分かりません。 :) –

答えて

6

各Timerオブジェクトに対応する単一のバックグラウンドスレッドです。

そしてpeeking to the inner code of the java.util.Timer classを見ると、基本的にnew Thread()を呼び出してスレッドをインスタンス化することがわかります。

一方、そのJavaサンドボックス内のスレッドの使用に関するApp Engine's documentationから:

あなたのスレッドを作成するために、ThreadManager上のいずれかの方法を使用する必要があります。 新しいThread()を自分で呼び出すことはできません。、またはデフォルトのスレッドファクトリを使用することはできません。

だから何ここで起こったことはTimerオブジェクトは、客観クエリを実行し、独自のスレッドをインスタンス化しますが、ThreadManager外のインスタンス化のスレッドが彼らのために設定し適切なApp EngineのAPI環境を持っていないので、それが例外をスローしています。

TimerクラスとTimerTaskクラスを使用せず、代わりに基本スレッドを使用するようにコードをリファクタリングする必要があります。たとえば、代わりに使用する:

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

... 

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

を代わりに使用することができます

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

ありがとう!私はこれを試してみる。私はちょうどcronジョブについて読んでいますが、代わりにそのアプローチを試す方が理にかなっていますか? –

+0

@choc:Cronsは最高で1分の細分性しか持たず、TimerTaskの置き換えには少し過剰すぎるようです。 TaskQueueの[etaMillisまたはcountdownMillis](https://developers.google.com/appengine/docs/java/taskqueue/overview-push#The_Rate_of_Task_Execution)が適しているかもしれませんが、ユースケースによって異なります。詳細なTimerTaskユースケースを別のStackOverflowの質問として投稿し、GAEで可能な解決策を尋ねる場合は、チャイムインすることができます。 –

+0

ありがとう!私はここで新しい質問をしました:http://stackoverflow.com/questions/15985309/periodically-delete-entries-in-objectify –

関連する問題