月別: 2011年1月

Task Queue Java API Overview

http://code.google.com/intl/en/appengine/docs/java/taskqueue/overview.html

Task Queue Java API Overview

タスクキューAPIでは、アプリケーションはユーザーリクエストによって開始される処理を、そのリクエストなしに実行できます? アプリがいくつかのバックグラウンド処理を実行する必要がある場合、その処理をタスクと呼ばれる小さい分離した単位に編成する為にタスクキューAPIを使うことができます。 その後、アプリは1本以上のキューにこれらのタスクを挿入することが出来ます。Appエンジンは自動的に新しいタスクを検出しシステムリソースが許す時にこれらのタスクを実行します。

 タスクキューの使用(Java)

Java appはWAR内部のWEB-INF/にあるqueue.xmlという名前の設定ファイルを使用してキューを設定します。Java タスクキュー設定を見てください。アプリがqueue.xmlファイルを持たない場合、いくつかのデフォルト設定がされているdefaultという名前のキューを持ちます。
タスクをキューに入れる為にQueueFactoryを使用してキューを取得し、それからキューのaddメソッドを呼び出します。 ファクトリクラスのgetQueue()メソッドを使用してqueue.xmlで指定した名前を付けたキューを取得するか、getDefaultQueue()メソッドを使用してデフォルトのキューを取得することが出来ます。TaskOptions.Builderによって産出したタスクオプションインスタンスを伴ったキューのadd() メソッドを呼び出すか、キュー用のデフォルトのオプションを伴ったタスクを作成する為に引数なしでadd()メソッドを呼び出すことが出来ます。
以下のコードはキューへオプションを伴ったタスクを追加します:

import com.google.appengine.api.taskqueue.Queue;
import com.google.appengine.api.taskqueue.QueueFactory;
import static com.google.appengine.api.taskqueue.TaskOptions.Builder.*;
// ...
       
Queue queue = QueueFactory.getDefaultQueue();
        queue
.add(url("/worker").param("key", key))

デフォルトキューはqueue.xmlファイルのタグで設定された割合か、またはデフォルトの一秒間に5件のタスクの割合でパラメータのkeyを伴ってURL/workerのリクエストハンドラ呼び出すでしょう。

 タスクの概念

Appエンジンのバックグラウンド処理では、タスクは小さな作業単位の完全な記述です。
 この記述は二つのパートを含みます:
  • タスクをパラメータ化したデータ本体
  • タスクを実装したコード
例えば、イベントが更新された時に招待客へEメールで通知する必要があるカレンダーアプリケーションを考えてみてください。この機能の為に”Eメール通知タスク”を以下のように定義します。
  • タスク – Eメール通知
    • データ: イベントの説明と招待客のEメールアドレスと名前
    • コード:  Eメールテンプレートに適切な文字列を代入し、メールを送信する機能.
おそらく発生したイベントを更新する必要のある招待客は複数います。開発者は各出席者への新しい通知タスクを個々に作成することを選択出来ます:
  • タスク 1
    • データ: 招待客1のEメールアドレス
    • コード: Eメールの機能 (Eメールの内容を準備し送信する)
  • タスク 2
    • データ: 招待客2のEメールアドレス
    • コード: Eメールの機能 (Eメールの内容を準備し送信する)
  • タスク 3
    • データ: 招待客3のEメールアドレス
    • コード: Eメールの機能 (Eメールの内容を準備し送信する)
この例が示すように、複数のタスクは同じ共通コードを共有し、そのデータの実体においてのみ異なることも可能です。同様にeコマースサイト用の以下のように複数のタスクは同じデータの実体を共有するけれども異なるコードを参照出来ます:
  • タスク 1 – バイヤーへレシートを送る
    • データ: 注文記述オブジェクト
    • コード: バイヤーにメールでレシートを送る機能
  • タスク 2 – トランザクションの初期化
    • データ: 注文記述オブジェクト (タスク1と同じ)
    • コード: 注文変更機能
より多くのタスクの例を含む場合:
  • フィードアグリゲーター。フィードリーダーアプリケーションは、自動的かつ周期的にインターネット中からさまざまなニュースの内容を取ってくる必要があります。シングルタスクは以下のものからなります:
    • データ: フィードのURLと最終チェック時刻
    • コード: フィードを取得するためのURLフェッチ、その内容の解析、データベースへ新アイテムの挿入を実行する機能

 オフラインWebフックとしてのタスク

App Engineが具体的なタスクインスタンスをサポートするために2つの機構が必要です:
  • データストレージ: 任意のデータ用の言語を選ばないコンテナ
  • コードリファレンス(コードへの参照、実際のコードを呼び出すことの出来るURL、ポインタ等?):パラメータで渡す方法を持つ、任意のコードを参照するための言語を選ばない機構
幸いなことに、インターネットは既にHTTPリクエストとそのレスポンスの形式でそのような解決策を提供しています。データの実体はwebフォームの変数、XML、JSONまたはエンコードされたバイナリデータのようなHTTPリクエストの内容です。コードリファレンスはURL自身です;実際のコードはサーバレスポンスの準備を行う際に実行するロジックです。  
上述のカレンダーアプリの例のタスクを以下のように改訂することが出来ます:
  • Task 1
    • data: eメールアドレス(参加者1のeメールアドレス)のフォーム変数を含んだHTTP POSTメッセージ 
    • code: HTTP POSTでリクエストされた時、メール送信するサーバサイドのコードを実行するURL
このモデルを使用して、App EngineのタスクキューAPIはHTTPリクエストとしてタスクを指定することが出来ます。(そのデータとしてリクエストの中身とそのコードリファレンスとしてのリクエストのターゲットURLの両方)  この方式で束ねられたHTTPリクエストへのプログラム的な参照は時に「web hook(ウェブフック)」と呼ばれます。
重要なことに、タスクキューAPIのオフラインの特徴?は実際の実行なしに事前にウェブフックを指定することが出来ます。従って、アプリケーションは一度に沢山のウェブフックを作成し、それからそれらをApp Engineに渡すことが出来ます; その後、システムはバックグラウンドで非同期でそれらを処理するでしょう。(HTTPリクエストを実行することによって)  このウェブフックモデルは効率的な並行処理を可能にします。App Engineは同時に複数のタスクまたはウェブフックを実行出来ます。
要約すると、タスクキューAPIは開発者がジョブをまとめてオフラインウェブフックにして非同期にバックグラウンドでジョブを実行することを可能にします。システムは、可能な限り並行して複数のウェブフックを実行することによる最適のパフォーマンスをスケジューリングし、アプリケーションのためにそれらのウェブフックを実行します。
HTTP標準に基づいた、この粒度のジョブ単位のモデルはApp Engineに任意のプログラミング言語またはwebアプリケーションフレームワークで動作する方法で効率的なバックグラウンド処理の実行を可能にします。

 ワーカーURLとタスクの名前

上述のように、タスクはURLによって自分自身の実装を参照します。例えばRSSフィードを取得して解析するタスクは、/app_worker/fetch_feed.というワーカーURLを使用するかもしれません。App Engine タスクキューAPIでは、あなたのwebアプリケーション内である限りタスク用のワーカーURLとしてどのようなURLも使用できます。全てのタスクワーカーURLは相対URLで指定されなければなりません。

import com.google.appengine.api.taskqueue.Queue;
import com.google.appengine.api.taskqueue.QueueFactory;
import com.google.appengine.api.taskqueue.TaskOptions.Method;
import com.google.appengine.api.taskqueue.TaskOptions.Builder.*;
// ...
       
Queue queue = QueueFactory.getDefaultQueue();

        queue
.add(url("/path/to/my/worker"));

        queue
.add(url("/path?a=b&c;=d").method(Method.GET));

タスクの内容(そのデータの実体とワーカーURL)に加えて、タスクの名前を指定することも出来ます。一旦、Nという名のタスクが書きこまれた場合、後からNと名付けられたタスクを挿入しようとするどんな試みも失敗するでしょう。通常、これがTrueの間、タスクネームは一回限りのセマンティクスの絶対的な保証を提供しません? ごく稀に同じ名前のタスクを作成するための複数のAPI呼び出しが成功するかもしれません。更に たとえそれが一回作られただけでもタスクが二回以上実行するタスクでの例外ケースもありえます?一回きりのセマンティクスが必要な場合は、データストアを使用してください。
タスクの作成が成功した場合、最終的にタスクは削除されます。(少なくてともタスクの実行の成功の七日後)
削除された場合、その名前を再利用することが出来ます。

 タスクリクエストヘッダ

タスクキューサービスからのリクエストは以下のHTTPヘッダを含みます:
  • X-AppEngine-QueueName, キューの名前 (或いは default)
  • X-AppEngine-TaskName, タスクの名前、または名前が無指定の場合はシステムが生成したユニークなID
  • X-AppEngine-TaskRetryCount, このタスクがリトライした回数; 最初の試行ではこの値は0です。 

 タスクのURLへのアクセス制限

アドミニストレータアカウント(管理者アカウント)へのアクセスを制限することによってユーザーがタスクのURLへアクセスすることを防ぐことが出来ます。タスクキューは管理者限定のURLへアクセスすることが出来ます。URLへのアクセス制限についてはセキュリティと認証 で読むことが出来ます。 web.xml を使用して /tasks/ で始まる全てのURLへのアクセスを管理者限定にする例です:

    
       

           
/tasks/*
       

       

           
admin
       

   

Note: タスクキューがadminでURLパス制限を使用している間は*のURLパス制限を使用することは出来ません。
web.xml,のより詳しい書式については配備記述子: web.xmlの文書を見てください。
タスクwebフックをテストする為にアドミニストレータとしてログインし、ブラウザでハンドラのURLへ行ってみてください。

 トランザクション内のタスク

トランザクションが成功裡にコミットされた場合にのみに待ち行列に追加され、追加されることが保証されているようなタスクをデータストア・トランザクションの一部としてキュー(待ち行列)に追加することが出来ます?トランザクションに追加されたタスクは、その一部として考えられisolation and consistency.の同じレベルを持ちます?(SERIALIZABLE?)
アプリケーションは一件のトランザクション処理中にtask queuesに5件を越えるtransactional tasksを挿入することは出来ません。トランザクションタスクはユーザー指定の名前を持ってはいけません。
        DatastoreService ds = DatastoreServiceFactory.getDatastoreService();
       
Queue queue = QueueFactory.getDefaultQueue();
       
try {
         
Transaction txn = ds.beginTransaction();

         
// ...

    queue
.add(TaskOptions.Builder.url("/path/to/my/worker"));

         
// ...
          txn
.commit();

         
} catch (DatastoreFailureException e) {

         
}

 タスク処理

タスクを作成し、処理キューに挿入するとAppエンジンは スケジュール判定基準が指定されていなければ出来るだけ早くそれを実行します。シングルタスクの実行のライフタイム(有効期間)は10分間に制限されています。もしタスクの実行が10分の制限に近づいた場合、Appエンジンは例外を投げるので、それを捕捉して処理または進行ログ?を保存することが出来ます。
開発者がキューへ待ち行列を挿入する場合、(他のタスクと関係する)タスクを実行する順序は内容とそのキューのプロパティによって決定されます。しかしながらタスク単位で特別なスケジュールをリクエストする、ETAのようなプロパティを指定することが出来ます。
タスクは実行に失敗した場合(200-299の範囲外のHTTPステイタスコードが返さることによって)、Appエンジンはそのタスクが成功するまでリトライします。システムは余りにも多すぎるリクエストでアプリケーション(の処理?)を溢れさせることを避ける為に漸進的に減らしますが、スケジュールリトライは最大一時間に一回、処理失敗タスクの再発を試みます?
さらにqueue.xmlretry-parameters elementを使用してタスクリトライのスキームを設定することも出来ます。

タスクのコードを(アプリケーションのワーカーURLとして)実装する場合、タスクが idempotent(冪等 べきとう)であるかどうかを考慮することが重要です。AppエンジンのタスクキューAPIは与えられたタスクを一度だけ起動するように設計されています。しかしながら、例外的な状況でタスクを複数回実行することはあり得ます。 (例えばたとえ主要システム障害でも?) したがって、あなたのコードは繰り返し実行された場合に有害な副作用がないことを保証しなければなりません。



冪等 べきとう…ある操作を1回行っても複数回行っても結果が同じであることをいう概念

タスクがセンシティブな操作(重要なデータの変更のような)を実行する場合、悪意ある社外ユーザーが直接ワーカーURLを呼び出さないようにワーカーURLを保護することを望むことが出来ます?

 キューの概念

ここまでこのドキュメントはどのようにタスクが非同期実行の為に小さな仕事のチャンク(塊)にカプセル化されて使用することが出来るかを説明してきました? 多数で使用される場合、タスクはバックグラウンド処理に対して効果的かつ強力なツールを提供します。しかしながらこれらのタスクの実行を管理する必要があるかもしれません。特にリソースを消耗しないようにタスクを起動するレートを管理する必要があるかもしれません。
タスクキューAPIはタスクのコンテナとしてキューを提供します。全ての新しいタスクはキューに挿入されなければなりません;キューのプロパティを変更することによってタスクの実行に影響を及ぼすことが出来ます。例として、システムが1秒間に10通のEメールのみを送信することを保証したいとします。1秒につき10件起動するレート(割合)に設定してあるemail-throttleと呼ばれるキューを使用することによりこれを達成することが出来ます。アプリケーションのコード内で、メールを送信する全てのタスクがこのemail-throttleキューに挿入されるようにします。
一瞬で数千件のタスクが挿入されても、Appエンジンシステムは email-throttle キューの設定を尊重し、1秒間に10件またはそれ以下のレートでそのタスクを起動します。
タスク実行レートへの影響の他に、さらにキューはシステムによって消化されるタスクの順序付けを提供します。(特別なタスクスケジュールパラメータには逆らいません) 基本的に、キューはベストエフォートFIFO(先入れ先出し)の順序で実行します。開発者は新しいタスクを作成し、それらをキューの最後に挿入します。システムは実行の為にキューの先頭からタスクを取り除きます。しかしながらシステムはスケジューラへの特別に最適化された通知によって与えられたタスクを出来るだけ最も低いレイテンシ(遅延時間)で実行を試みます。したがってキューが処理すべき多数のタスクを抱えている場合、システムのスケジュールは新しいタスクをキューの先頭へジャンプさせます。
キューは一般的なFIFOの順序付けを定義しますが、タスクは完全に順番通りに実行されるわけではありません。一つのキューからの複数のタスクはスケジューラーによって同時に実行されるかも知れないので、通常のロックとトランザクションセマンティクスはタスクによって実行される処理のために監視される必要があります?
概してキューはタスクを操作するためのメカニズムであると理解することが重要です;キューは与えられたタスクの内容を指図しません。一つのキューに、様々なデータ実体とワーカーURLを持つ、多くの異なるタイプのタスクを含めることが出来ます。

 デフォルトキュー

便宜上、Appエンジンは全てのアプリケーションにデフォルトキューを提供します。如何なる追加設定もなしに、このキューを直接使用することが出来ます。このキューは自動的に1秒間に5件のタスクの処理レートを持ちます。しかしながら、
defaultという名のキュー用の設定をどんなユーザー定義キューにも同じ方法でそのプロパティを設定することが出来ます?コードは常にデフォルトキューに新しいタスクを挿入できますが、もしこれらのタスクの実行を無効にしたい場合、defaultを設定に追加してそのタグで0に下げればそうなります?

 キューデフォルトURL

タスクオブジェクトコンストラクタにワーカーURLを渡すことによってタスク用に指定することが出来ます。
ワーカーURLを指定しない場合、タスクはキューの後に名付けられたデフォルトワーカーURLを使用します。 
/_ah/queue/queue_name
例として、email-worker-queue, という名のキュー用に/_ah/queue/email-worker-queue (アプリケーション内)にデフォルトリクエストハンドラを実装出来ます。それ自身のワーカーURLを持たず email-worker-queueに挿入された新しいタスク(言い換えるとコードリファレンスを持たない純粋なデータ)は、URL /_ah/queue/email-worker-queueを使用して起動されます。
キューデフォルトURLはタスクがそれ自身のワーカーURLを持たない場合にのみ使用されます。タスクがそれ自身のワーカーURLを持っている場合、それは決して他のではなくデフォルトURLでのみ起動されます?(一旦キューに挿入されるとタスクは不変です) 
タスクがワーカーURLを持っていない場合、たとえ現在キューデフォルトURLにハンドラが定義されていなくてもタスクはキューデフォルトURLを起動することに注意してください!この場合、システムは404エラーで失敗する存在しないURLでタスクを起動することを試みます。(この404は、トライされた正確なURLとともにアプリケーションログで利用可能です。) この404の失敗状態の結果、システムはタスクを保存し、最終的に成功するまでリトライします。管理コンソールを使用して完了することが出来ないタスクを一掃(または’粛清’)出来ます。

 タスクとアプリケーションバージョン

アプリケーションの全てのバージョンは同じタスクキューを共有します。タスクを実行する為に使用されるアプリのバージョンはどのようにタスクのキューに入れられたかに依存します。
タスクをキューに入れるアプリのバージョンがデフォルトバージョン(http://app-id.appspot.com またはGoogle Apps ドメイン)の場合、キューはタスクを実行するためにデフォルトバージョンのアプリを使用します。たとえタスクがキューに入れられた後にデフォルトバージョンが変更されていてもです。

アプリがタスクをキューに入れ、それからデフォルトバージョンが変更された場合、キューはタスクを実行するためのアプリの新しいデフォルトバージョンを伴ったタスクURLを使用します。

タスクをキューに入れたアプリのバージョンが( http://3.latest.app-id.appspot.com/のように) タスクをキューに入れた時のデフォルトバージョンではない場合、どのバージョンがデフォルトバージョンであるかに関わらず、キューはタスクを実行するためにそのキューに入れたバージョンのアプリを使用します。

 管理コンソールでのタスクキュー

管理コンソールを使用してアプリケーション用のタスクキューを管理出来ます。コンソールを使って以下のことが出来ます:
  • キューとその設定の一覧取得
  • 現在の実行待ちしているタスクの点検
  • キューの実行の一時停止
  • 独立したタスクの直ちに実行します。タスクの隣にある”Run Now”ボタンをクリックすると、Appエンジンはたとえキューが一時停止されていても、そのタスクを実行します。直ちにタスクを実行することはアプリケーションエラーを診断するのに役立ちます。
  • キュー内の個々のタスクまたはタスク全ての手動削除。これは完了することが出来なかったりリトライ待ちで動けないタスクで役に立ちます。
キューを管理する為に、管理コンソールへログインし、”Task Queues”を選択してください。に注意してください。 デフォルトキューはアプリがタスクを初めていれた後でのみコンソールで表示されることに注意してください。

 タスクキューと開発サーバ

アプリを開発サーバで動かした時、タスクは自動的にプロダクション環境下のように適切な時間で実行されます。しかしながら、あなたが知っておくべき開発サーバとプロダクション環境での振る舞いに小さな違いがあります。第一に、開発サーバはキュー属性”レート”、”パケットサイズ”を考慮しません。 結果として、タスクは出来るだけスケジュールされた実行時間の近くで実行され、タスクが自動的に実行されることを妨げないようにレートが0に設定されます?第二に、開発サーバはリトライしません。最後に開発サーバはサーバ再起動時にキューの状態を保存しません。将来のリリースで、開発サーバでもこれらの機能のサポートを実装するつもりです。
タスクの自動実行を無効にするにはjvm flagに”task_queue.disable_auto_task_execution”を設定します:
 --jvm_flag=-Dtask_queue.disable_auto_task_execution=true
開発者コンソールからタスクを調べたり操作することが出来ます:

http://localhost:8080/_ah/admin/taskqueue

タスクを実行するには、その名前をクリックすることによりキューを選択し、それから実行するタスクを選択します。任意のタスクを実行することなしにキューを空にするには”Purge Queue”ボタンをクリックします。

 クォータ(割当)と制限

タスクをキューに入れることは以下のクォータでカウントします:
  • Task Queue Stored Task Count
  • Task Queue Stored Task Bytes
“Task Queue Stored Task Bytes quota”はqueue.xmlのTotalStorageLimitをセットすることによって設定出来ます。
このクォータは”Stored Data (billable) quota”でカウントします?
タスクの実行は以下のクォータでカウントします:
  • Requests
  • CPU Time
  • Incoming Bandwidth
  • Outgoing Bandwidth
リクエストハンドラがリモートクライアントに呼び出されたかのように、タスクを実行する行為は リクエストとレスポンスデータ用の帯域幅に関連したクォータを消費します。タスクキューがタスクを処理した時、レスポンスデータは廃棄されます。
タスクを実行または削除されたら、そのタスクで使用されていたストレージは回収されます。タスク用のストレージクォータの回収は定期的に発生します。これはタスクを削除した後、すぐにストレージクォータに反映されないかもしれません。
割り当ての詳細については、割り当て、および管理コンソールの「割り当て詳細」セクションをご覧ください。
割り当てに加え、タスクキューの使用には次の制限があります:
制限 制限値
タスクオブジェクトサイズ 10 KB
アクティブキューの数 (デフォルトキューを含まない) 無料使用のアプリの場合、10
有料使用のアプリの場合、100
キューの実行レート 1本のキューにつき毎秒50タスク起動
タスク用のカウントダウン/ETA の最大値 現在の日時から30日
バッチで追加できるタスクの最大数 100 タスク
※ETA(Estimate Time of Arrival)到着予定時刻、復旧予定時間(ETR?) 

 タスクキューAPIのステイタス

Appエンジンのタスクキューは現在、その最終的なロケーションで利用可能です:
com.google.appengine.api.taskqueue 
Appエンジンのタスクキューの以前のロケーションは現在、非推奨です。もしグーグルラボの頃のAppエンジンタスクキューAPIを使用している場合は、非推奨警告を除去するためにコードを更新してください。