GAE + GWT プログラミングメモ

Google App Engine とGoogle Web Toolkit のメモ

Cron+TaskQueue+Backendsで定期実行

作成中のアニメ特化アンテナサイト
http://kumo2ji.appspot.com/

Cronはタスクを1時間に1回、1週間に1回など定期的間隔で実行するための仕組み。
TaskQueueは時間のかかるタスクをいくつかのQueueに分割して実行するための仕組み。
BackendsはFrontendと別に用意されたリソース。無料分がFrontendと別に用意されている。

この3つを組み合わせて無料リソースを最大限利用して、比較的時間のかかる処理を定期的に実行する。

まずはBackendインスタンスを作成する。
WEB-INF/backends.xmlを作成し、インスタンスの設定を記述する。

<backends>
  <backend name="b1">
    <class>B1</class>
   <options>
     <dynamic>true</dynamic>
   </options>
  </backend>
</backends>

次に、CronとTaskQueueのリクエストを受け取るためのServletを作成する。
ここでは、例として、アマゾンの商品情報をDatastoreに保存するstoreItemメソッドをアニメ数分行う処理を考える。
StoreAmazonItemServletはCronからはdoGetが呼ばれ、TaskQueueからはdoPostが呼ばれる。
Cronから呼ばれるdoGetでは、QueueFactory.getQueue("StoreAmazonItemServlet")でQueueを作成する。
getQueueの引数はqueue.xmlで指定するキュー名である。
queueには、パラメータとHostヘッダーを指定する。
このヘッダーがTaskQueueをBackendで実行するために必要な情報となる。
getBackendAddressの引数はbackends.xmlで指定したbackendの名前。

TaskQueueにより実行されるdoPostでは、storeItemメソッドを実行する。
この例では、doGetでアニメの数だけQueueが追加されたので、その回数分、doPostが呼ばれることになる。

public class StoreAmazonItemServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;
	
	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {
		AmazonService service = new AmazonService();
		service.storeItem(req.getParameter("animeKeyword"));
	}

	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {
		AnimeService service = new AnimeService();
                Queue queue = QueueFactory.getQueue("StoreAmazonItemServlet");
		for (String keyword : service.getAnimeList()) {
			queue.add(TaskOptions.Builder
				.withParam("animeKeyword", keyword)
				.header("Host", BackendServiceFactory.getBackendService().getBackendAddress("b1")));
		}
	}
}

このServletをweb.xmlに登録する。
queueはURLを指定しない場合、/_ah/queue/[キュー名]が使用されるので、そのように指定している。

<servlet>
    <servlet-name>StoreAmazonItemServlet</servlet-name>
    <servlet-class>com.kumo2ji.server.StoreAmazonItemServlet</servlet-class>
  </servlet>
  
  <servlet-mapping>
    <servlet-name>StoreAmazonItemServlet</servlet-name>
    <url-pattern>/_ah/queue/StoreAmazonItemServlet</url-pattern>
  </servlet-mapping>

WEB-INF/cron.xmlのurlにも/_ah/queue/StoreAmazonItemServletを指定することで、TaskQueueと同じServletを使用する。
もちろん異なるServletを用意し、それぞれに指定してもよい。
targetにbackends.xmlのbackend名を指定することで、CronをBackendで実行することができる。

<?xml version="1.0" encoding="UTF-8"?>
<cronentries>
  <cron>
    <url>/_ah/queue/StoreAmazonItemServlet</url>
    <description>store Amazon item entry</description>
    <schedule>every day 00:00</schedule>
    <target>b1</target>
  </cron>
</cronentries>

最後にWEB-INF/queue.xmlにTaskQueueを登録すれば、完了。

<queue-entries>
  <queue>
    <name>StoreAmazonItemServlet</name>
    <rate>2/m</rate>
  </queue>
</queue-entries>

Cronはデバッグ環境では、実行されないので、本番環境にデプロイして、動作確認する。