Django中的Celery periodic_task运行一次(!)

时间:2013-08-25 13:20:58

标签: python django celery

我正在创建一个使用celery和Django的periodic_task,我想每隔X秒运行一次。 该任务应该产生几个子任务,但我需要确保每个主要任务只产生一组子任务。

这就是我的......

@periodic_task(run_every=datetime.timedelta(seconds=2))
def initialize_new_jobs():
    for obj in Queue.objects.filter(status__in=['I', 'Q']):
        obj = Queue.objects.get(id=obj.id)
        if obj.status not in ['I', 'Q']:
            continue
        obj.status = 'A'
        obj.save()
        create_other_task.delay(obj.id)

这种方法有效,但感觉不对。我必须在循环开始时刷新obj,以确保另一个正在运行的periodic_task不会在同一个Queue对象上发出create_other_task。

有没有更好的办法做这种工作?基本上,我想尽可能多地执行create_other_task,但只有每个Queue对象的ONCE状态为I或Q.

这是我的问题的缩短版本,所以请忽略我在创建Queue对象时可以运行create_other_task而不是运行定期任务的事实:)

1 个答案:

答案 0 :(得分:1)

您可以使用交易:

@periodic_task(run_every=datetime.timedelta(seconds=2))
@transaction.commit_on_success
def initialize_new_jobs():
    for obj in Queue.objects.select_for_update().filter(status__in=['I', 'Q']):
        obj.status = 'A'
        obj.save()
        create_other_task.delay(obj.id)

select_for_update()对行进行独占锁定,以便在尝试读取值时阻止其他用户。事务提交或回滚后释放锁。 Reference

通过这种方式,您可以确保obj的状态为IQ,并且obj.save()可以正常运行。