taskqueue.add に transactional という kwargs を発見したので使い途を考えていたのですが、例えば Entity が put された時にメールを一通送信したいというケースに使えるのではないかと考えています。
まずはこの transactional がどんな効果があるか説明しておきましょう。db の transaction 内で transactional=True を指定して taskqueue.add を実行すると、その transaction が成功した時のみ queue に task が積まれます。
では put 時のメール送信を taskqueue 無しで実装してみましょう。下記のコードは拙作の Kay を使用しています。Kay について知らない場合でも、コード自体単純なので pseudo コードとして読んでもらえれば良いかなと思います。
def add_entity(request):
# まず Post 値(request.form)を元に Entity を Put
new_entity = MyModel(name=request.form.get('name'))
new_entity.put()
# 次にメール送信
my_send_mail()
# クライアントにレスポンスを返す
return Response("New entity saved.")
このコードだと、db のオペレーションが成功した後にメール送信が失敗した場合に db とメール送信状況に齟齬が生じます。API の呼出し順を変えても問題は解消しません。
そこで transactional な taskqueue を使用する事を考えます。
def send_mail(request):
# taskqueue で呼ぶハンドラです
if my_send_mail():
# 成功した時だけ 200
return Response("OK")
else:
# 失敗したら 500(Retryするはず)
raise InternalServerError()
def add_entity(request):
# トランザクションで実行する inner メソッドを定義
def txn():
# まずは taskqueue.add を呼ぶ
taskqueue.add('/send_mail', transactional=True)
# 次に Post 値(request.form)を元に Entity を Put
new_entity = MyModel(name=request.form.get('name'))
new_entity.put()
return new_entity
# transaction を実行(本当はエラー処理した方が良い)
db.run_in_transaction(txn)
# クライアントにレスポンスを返す
return Response("New entity saved.")
こうしておくと transaction が成功した場合のみ task が積まれます。また my_send_mail() 呼び出しが失敗したら 500 を返す事で、task をリトライする事ができます。唯一 my_send_mail() が終了してから 200 を返す前に DeadLineExceededError 等になった場合のみ不整合が発生します。Entity個別の情報が必要な場合は、予め id を割り当てる必要があるかもしれません。
論理的にはこれで実用に耐えうるんじゃないかと思いますが、なんせまだ机上で考えただけで実際には試してないので、いずれ試してみたいと思います。