オブジェクトをデータベースに保存するDjangoアプリケーションと、それらのオブジェクトのいくつかで定期的に処理を行うセロリのタスクがあります。問題は、のオブジェクトを処理するためにセロリタスクによって選択されたの後に削除できますが、の前には、のセロリタスクが実際に処理および保存を完了しています。したがって、セールスタスクが.save()
を呼び出すと、オブジェクトが削除されたにもかかわらずオブジェクトがデータベースに再表示されます。もちろん、ユーザーのために本当にうんざりです。オブジェクトやベールがDjangoで削除された場合の更新方法
そこでここでは問題を示すいくつかのコードです:
def my_delete_view(request, pk):
thing = Thing.objects.get(pk=pk)
thing.delete()
return HttpResponseRedirect('yay')
@app.task
def my_periodic_task():
things = get_things_for_processing()
# if the delete happens anywhere between here and the .save(), we're hosed
for thing in things:
process_thing(thing) # could take a LONG time
thing.save()
私はアトミック・ブロックとオブジェクトが実際にそれを保存する前に存在しているかどうかをテストするには、トランザクションを追加することによって、それを修正しようと考えました:
@app.task
def my_periodic_task():
things = Thing.objects.filter(...some criteria...)
for thing in things:
process_thing(thing) # could take a LONG time
try:
with transaction.atomic():
# just see if it still exists:
unused = Thing.objects.select_for_update().get(pk=thing.pk)
# no exception means it exists. go ahead and save the
# processed version that has all of our updates.
thing.save()
except Thing.DoesNotExist:
logger.warning("Processed thing vanished")
これはこの種のことを行う正しいパターンですか?私はそれが生産でそれを実行して数日以内に動作するかどうかを調べるでしょうが、この種のものを達成するための他のよく受け入れられているパターンがあるかどうかを知ることはうれしいでしょう。
私が本当に望むのは、データベースにまだが存在する場合は、オブジェクトを更新できることです。 process_thing
のユーザー編集と編集の間の競争は大丈夫ですが、process_thing
の直前にrefresh_from_db
を入れてユーザーの編集内容を失う時間を最小限に抑えることができます。しかし、私は間違いなく、ユーザーがそれらを削除した後にオブジェクトを再表示させることはできません。あなたがセロリのタスクの処理時間のためにトランザクションを開いた場合
私によく似ています – dkarchmer