きしだのはてな このページをアンテナに追加 RSSフィード

2010-01-25(月)

Google App Engineで長い処理をタスクキュー使って実行 14:54 Google App Engineで長い処理をタスクキュー使って実行を含むブックマーク

Google App Engineだと、30秒制限があって長い処理が書きにくいのですが、タスクキューは処理中に例外が発生したり30秒制限にひっかかったりすると自動的に呼び直されるので、これを使って長い処理を実行することができます。

ということは知っていたんだけど、実際どうなのかと思って試してみた。


まずこんなサーブレット書きます。

※GAE/JはServlet3.0に対応してないので、@WebServletアノテーション擬似コードだと思ってください。

5秒に一回QueueTestに現在値を記録するという処理を行うループを20回繰り返します。5秒×20=100秒 >> 30秒なので、確実にタイムアウトします。

タスク開始時の値をQueueLogに記録しておきます。

@WebServlet(urlPatterns="/queue/testqueue")
public class TestQueueServlet extends HttpServlet {

    protected void doGet(HttpServletRequest request, HttpServletResponse response)
    throws ServletException, IOException {
        DatastoreService ds = DatastoreServiceFactory.getDatastoreService();
        Entity ent;
        Key key = KeyFactory.createKey("QueueTest", 1);
        try {
            ent = ds.get(key);
        } catch (EntityNotFoundException ex) {
            ent = new Entity(key);
            ent.setProperty("count", 0L);
        }
        Entity log = new Entity("QueueLog");
        log.setProperty("count", ent.getProperty("count"));
        log.setProperty("updated", new Date());
        ds.put(log);

        Long lg = (Long) ent.getProperty("count");
        for(; lg < 20; ++lg){
            try {
                Thread.sleep(1000 * 5);
                ent.setProperty("count", lg);
                ent.setProperty("updated", new Date());
                ds.put(ent);
            } catch (InterruptedException ex) {
            }
        }
    } 
}

そしたら、こんな感じでQueueに入れます。

@WebServlet(urlPatterns="/queuetest");
public class QueueTestServlet extends HttpServlet {

    protected void doGet(HttpServletRequest request, HttpServletResponse response)
    throws ServletException, IOException {
        Queue q = QueueFactory.getDefaultQueue();
        q.add(TaskOptions.Builder.url("/queue/testqueue"));

        response.setContentType("text/html;charset=UTF-8");
        PrintWriter out = response.getWriter();
        out.println("<title>Servlet QueueTestServlet</title>");  
        out.println("queued");
        out.close();
    } 
}

このサーブレットを呼び出してしばらくほっておくと、QueueLogにデータがたまります。だいたいこんな感じで実行されました。

 0: 04:41:09
 4: 04:43:34
 8: 04:44:33
12: 04:45:10
16: 04:45:47

処理が終わったのは 04:46:07となってたので、ほぼ5分かかったことになります。

4回の繰り返し、つまり20秒以上たって一度の呼び出しが終わっていることもわかります。

機嫌がいいときには40秒以内でタスクキューの処理が繰り返されてますが、1分近くかかっていることもあります。


100秒=1分40秒の処理に、5分=300秒かかるというのがどうかというのはありますが、ともあれ、タスクキューを使って長い処理が実行できることが確認できました。