如何避免芹菜任务的竞争条件?

How to avoid race conditions on celery tasks?

考虑以下任务:

@app.task(ignore_result=True)
def withdraw(user, requested_amount):
    if user.balance >= requested_amount:
        send_money(requested_amount)
        user.balance -= requested_amount
        user.save()

如果这个任务被同时执行两次,会导致用户余额为负...我该如何解决?这只是种族的一个例子,但我的代码中有很多这样的情况..

您可以使用 this Celery cookbook recipe to implement a Lock which will make sure that only one task is run at a time, and then perhaps implement retry 逻辑稍后再尝试第二个任务。像这样;

def import_feed(self, feed_url):
    # The cache key consists of the task name and the MD5 digest
    # of the feed URL.
    feed_url_hexdigest = md5(feed_url).hexdigest()
    lock_id = '{0}-lock-{1}'.format(self.name, feed_url_hexdigest)
    logger.debug('Importing feed: %s', feed_url)
    with memcache_lock(lock_id, self.app.oid) as acquired:
        if acquired:
            return Feed.objects.import_feed(feed_url).url
    self.retry(countdown = 2)