我有一个Django应用程序将对象保存到数据库和一个芹菜任务,定期对其中一些对象进行一些处理。问题是用户可以在celery任务选择之后删除对象进行处理,但之前芹菜任务实际上已完成处理并保存它。因此,当celery任务调用.save()
时,即使用户删除了对象,该对象也会重新出现在数据库中。当然,这对用户来说真的很怪异。
所以这里有一些显示问题的代码:
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
的修改之间的竞争感到满意,我总是可以在refresh_from_db
之前加入process_thing
,以最大限度地缩短用户编辑的时间丢失。但是在用户删除对象后,我肯定无法重新出现对象。
答案 0 :(得分:0)
如果你在处理芹菜任务时打开一个交易,你应该避免这样的问题:
@app.task
@transaction.atomic
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()
有时,您希望向前端报告您正在处理数据,因此您可以将select_for_update()
添加到您的查询集(最有可能是在get_things_for_processing中),然后在负责删除的代码中在db报告特定记录被锁定时处理错误。
答案 1 :(得分:-1)
现在,似乎“原子地再次选择,然后保存”的模式就足够了:
@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")
(这与我原来的问题中的代码相同)。