提交事务时释放芹菜锁

2024-05-13 19:23:40 发布

您现在位置:Python中文网/ 问答频道 /正文

我在我的Django项目中使用了一个芹菜任务,锁如this article所述。它工作得很好,但是我的任务创建了一个对象,我不希望在将对象提交到数据库之前释放锁。如何更改此上下文管理器以等待任务中的对象被提交?在

@contextmanager
def lock(lock_id, oid, expire=600):
    timeout_at = monotonic() + expire - 3
    status = cache.add(lock_id, oid, expire)
    try:
        yield status
    finally:
        if monotonic() < timeout_at:
            cache.delete(lock_id)

@celery.task(bind=True, ignore_result=True)
def my_task(self, object_id):
    with lock('my_task.{}'.format(object_id), self.app.oid) as acquired, transaction.atomic():
        if not acquired:
            self.retry(countdown=1)
        def on_commit():
            # release the lock only in this moment
            pass
        transaction.on_commit(on_commit)
        MyModel.objects.create(object_id=object_id)

Tags: 对象selfidlocktaskobjectondef
1条回答
网友
1楼 · 发布于 2024-05-13 19:23:40

此上下文管理器在事务中创建锁并包装主体。它只在提交事务或引发异常(除了celery.exceptions.Retry)时才释放锁。在

如芹菜文献所述:

In order for this to work correctly you need to be using a cache backend where the .add operation is atomic. memcached is known to work well for this purpose.

from celery.exceptions import Retry
from contextlib import contextmanager
from time import monotonic
from django.core.cache import cache
from django.db import transaction


@contextmanager
def lock_transaction(lock_id, oid, expire=600):
    status = cache.add(lock_id, oid, expire)
    timeout_at = monotonic() + expire - 3
    is_retry = False

    def on_commit():
        if not is_retry and monotonic() < timeout_at:
            cache.delete(lock_id)

    with transaction.atomic():
        transaction.on_commit(on_commit)
        try:
            yield status
        except Retry as e:
            is_retry = True
        except:
            if monotonic() < timeout_at:
                cache.delete(lock_id)
            raise

使用示例:

^{pr2}$

相关问题 更多 >