タスクチェーンによる30秒制限を超えた処理を試す
タスクチェーンについてよくわかっていなかったので、実験してみました。
実装にあたっては下記を参考にさせていただきました。
Togetter - 「タスクキューのチェインについて」
Togetter - 「タスクキューのチェインについて2(Mapper APIで代替も検討?)」
Togetter - 「DeadlineExceedException発生時のリトライについて」
実際のソースコード
import static com.google.appengine.api.labs.taskqueue.TaskOptions.Builder.*; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.TimeZone; import java.util.logging.Logger; import org.slim3.controller.Controller; import org.slim3.controller.Navigation; import org.slim3.datastore.Datastore; import slim3ships.model.Slim3Model; import com.google.appengine.api.datastore.Key; import com.google.appengine.api.labs.taskqueue.Queue; import com.google.appengine.api.labs.taskqueue.QueueFactory; import com.google.appengine.repackaged.com.google.common.collect.Lists; import com.google.apphosting.api.DeadlineExceededException; public class ClearController extends Controller { private static Logger log = Logger.getLogger(ClearController.class.getName()); @Override public Navigation run() throws Exception { String triggerTaskName = request.getHeader("X-AppEngine-TaskName"); if (triggerTaskName == null) { log.info("[job start]"); // (1)(2)※ジョブの開始 } else { log.info("[job taskName]:" + triggerTaskName); //(2)※2回目以降 } List<Key> keys = Datastore.query(Slim3Model.class).asKeyList();//(3) try { List<Key> partOfKeys = Lists.newArrayList(); for (Key key : keys) { //(4) partOfKeys.add(key); if (partOfKeys.size() == 100) { Datastore.delete(key);//(5) partOfKeys.clear(); } } Datastore.delete(keys); response.setContentType("text/plain"); response.getWriter().println("delete completed. total size:" + Datastore.query(Slim3Model.class).count()); response.flushBuffer(); response.getWriter().close(); log.info("[job end]"); //(9) } catch (DeadlineExceededException e) { //(6) String taskName = "task" + format(new Date()); Queue queue = QueueFactory.getDefaultQueue(); queue.add(url("/lab/Clear").taskName(taskName));//(7) response.setContentType("text/plain;charset=utf-8"); response.getWriter().println("処理は次のtaskに引き継がれました:" + taskName); response.flushBuffer(); } return null;//(8) ,(10) } private String format(Date date) { SimpleDateFormat f = new SimpleDateFormat("yyyyMMddHHmmss"); f.setTimeZone(TimeZone.getTimeZone("Asia/Tokyo")); return "task" + f.format(date); } }
実行結果
タスクがチェーンされて、2回目のチェーンでジョブが完了されました。
I 09-12 11:48PM 02.903 slim3ships.controller.lab.ClearController run: [job end]
I 09-12 11:48PM 01.292 slim3ships.controller.lab.ClearController run: [job taskName]:tasktask20100913154800
I 09-12 11:47PM 32.262 slim3ships.controller.lab.ClearController run: [job taskName]:tasktask20100913154731
I 09-12 11:47PM 02.350 slim3ships.controller.lab.ClearController run: [job start]
疑問点
- DEEでTQに失敗したら、HardDeadlineExceedErrorのときにリトライする、というようなのを見かけたけどHardDreadlineExceedErrorの発生後にどうやって処理するのか?(catchできないのでは?)
- とぅぎゃり内で「エラーリトライしてもいいようにタスクは冪等にする」とのことだったが、上記は冪等になっていない。上記はべきとうにしないとまずいケースか?すべきならどうやって冪等にすべきか?param()でkeyのかたまりを投げる?