跳转到主要内容

通过redis的SETNX/BLPOP实现锁的上下文管理器。

项目描述

通过redis的SETNX/BLPOP实现锁的上下文管理器。

  • 免费软件:BSD 2-Clause许可证

接口目标是完全类似于threading.Lock

用法

因为我们不想要求用户在进程间共享锁实例,所以您必须给他们命名。

from redis import Redis
conn = Redis()

import redis_lock
lock = redis_lock.Lock(conn, "name-of-the-lock")
if lock.acquire(blocking=False):
    print("Got the lock.")
    lock.release()
else:
    print("Someone else has the lock.")

作为上下文管理器的锁

conn = StrictRedis()
with redis_lock.Lock(conn, "name-of-the-lock"):
    print("Got the lock. Doing some work ...")
    time.sleep(5)

您还可以将一个标识符与锁相关联,以便稍后由相同的进程或不同的进程检索。这在应用程序需要识别锁所有者(找出谁目前拥有锁)的情况下很有用。

import socket
host_id = "owned-by-%s" % socket.gethostname()
lock = redis_lock.Lock(conn, "name-of-the-lock", id=host_id)
if lock.acquire(blocking=False):
    assert lock.locked() is True
    print("Got the lock.")
    lock.release()
else:
    if lock.get_owner_id() == host_id:
        print("I already acquired this in another process.")
    else:
        print("The lock is held on another machine.")

避免在django中发生犬群效应

犬群效应也称为雷鸣群效应或缓存溃败。以下是一种避免问题而不提供陈旧数据的方法。工作将只执行一次,每个客户端都将等待新鲜数据。

要使用此功能,您需要安装django-redis,然而,python-redis-lock提供了一种方便的缓存后端,它为您提供了缓存方法。只需按照这种方式安装python-redis-lock

pip install "python-redis-lock[django]"

现在将以下内容放入您的设置中

CACHES = {
    'default': {
        'BACKEND': 'redis_lock.django_cache.RedisCache',
        'LOCATION': 'redis://127.0.0.1:6379/1',
        'OPTIONS': {
            'CLIENT_CLASS': 'django_redis.client.DefaultClient'
        }
    }
}

此后端仅为django-redis的缓存后端添加了一个方便的.lock(name, expire=None)函数。

您可以像这样编写您的函数

from django.core.cache import cache

def function():
    val = cache.get(key)
    if not val:
        with cache.lock(key):
            val = cache.get(key)
            if not val:
                # DO EXPENSIVE WORK
                val = ...
                cache.set(key, value)
    return val

故障排除

在某些情况下,锁会永远保留在Redis中(例如服务器断电/Redis或应用程序崩溃/未处理的异常)。在这种情况下,重启应用程序不会删除锁。一种解决方案是同时开启auto_renewal参数和expire,为锁设置超时时间,但让Lock()在您的应用程序代码执行期间自动重置超时时间。

# Get a lock with a 60-second lifetime but keep renewing it automatically
# to ensure the lock is held for as long as the Python process is running.
with redis_lock.Lock(conn, name='my-lock', expire=60, auto_renewal=True):
    # Do work....

另一种解决方案是在应用程序启动时使用reset_all()函数。

# On application start/restart
import redis_lock
redis_lock.reset_all()

或者,您可以通过reset方法重置单个锁。

请谨慎使用,如果您了解自己在做什么。

特性

  • 基于标准的SETNX配方

  • 可选过期时间

  • 可选超时时间

  • 可选锁续期(使用较短的过期时间但保持锁活动状态)

  • 获取时没有自旋循环

实现

redis_lock将为每个锁使用两个键,键名为<name>

  • lock:<name> - 实际锁的字符串值

  • lock-signal:<name> - 信号列表,用于在锁释放时通知等待者

它的工作原理是这样的

python-redis-lock flow diagram

文档

https://python-redis-lock.readthedocs.io/en/latest/

开发

要运行所有测试,请运行

tox

需求

操作系统:

任何

运行时间:

Python 2.7, 3.3或更高版本,或PyPy

服务:

Redis 2.6.12或更高版本。

类似项目

变更日志

4.0.0 (2022-10-17)

  • 删除了对Python 2.7和3.6的支持。

  • 从Travis切换到GitHub Actions。

  • 使日志消息更一致。

  • redis_lock.refresh.thread.*日志记录器替换为单个redis_lock.refresh.thread日志记录器。

  • 对各种测试进行了清理(主要删除了硬编码的临时路径)。

3.7.0 (2020-11-20)

  • 使记录器名称更具体。现在可以对这些新记录器名称进行粒度过滤

    • redis_lock.acquire(发出DEBUG消息)

    • redis_lock.acquire(发出WARN消息)

    • redis_lock.acquire(发出INFO消息)

    • redis_lock.refresh.thread.start (发出 DEBUG 消息)

    • redis_lock.refresh.thread.exit (发出 DEBUG 消息)

    • redis_lock.refresh.start (发出 DEBUG 消息)

    • redis_lock.refresh.shutdown (发出 DEBUG 消息)

    • redis_lock.refresh.exit (发出 DEBUG 消息)

    • redis_lock.release (发出 DEBUG 消息)

    由 Salomon Smeke Cohen 在 80 中贡献。

  • 修复了一些关于文档检查的 CI 问题。由 Salomon Smeke Cohen 在 81 中贡献。

3.6.0 (2020-07-23)

  • 改进了 timeout/expire 验证,以便

    • timeoutexpire 如果是假值,将转换为 ``None``。之前只有 None 禁用这些选项,其他假值会创建有问题的场景。

    • 现在允许使用大于 expiretimeout,如果 auto_renewal 设置为 True。之前会引发 TimeoutTooLarge 错误。见 74

    • 不允许使用负数的 timeoutexpire。之前允许这样的值,并会创建有问题的场景。见 73

  • 更新了基准测试和示例。

  • 移除了自定义脚本缓存代码。现在使用 redis 客户端的 register_script 方法。这在理论上将修复与 redis 集群相关的可能问题,因为 redis 客户端对此有一些特定的处理。

3.5.0 (2020-01-13)

  • 添加了 locked 方法。由 Artem Slobodkin 在 72 中贡献。

3.4.0 (2019-12-06)

  • 修复了可能导致某些配置中的死锁或缓慢的回归问题。见:71

3.3.1 (2019-01-19)

  • 修复了在运行 python-redis-lock 3.3 和 3.2 时的失败情况。见:64

3.3.0 (2019-01-17)

  • 修复了使用废弃的 warnings API 的问题。由 Julie MacDonell 在 54 中贡献。

  • RedisCache.lock (Django 缓存后端包装器) 中添加了 auto_renewal 选项。由 c 在 55 中贡献。

  • 将“%(script)s not cached”的日志级别从 WARNING 更改为 INFO。

  • 添加了对使用 decode_responses=True 的支持。锁键现在是纯 ASCII。

3.2.0 (2016-10-29)

  • 修改了信号键清理操作,不使用任何过期时间。这可以防止某些时间后仍存在残留键。由 Andrew Pashkin 在 38 中贡献。

  • 允许具有给定 id 的锁获取。之前它假设如果指定了 id,则锁已被获取。见 4439

  • 允许使用具有 strict=False 的其他 redis 客户端。通常期望传入一个 redis.StrictRedis 实例。

  • 向 Django 缓存后端添加了便利方法 locked_get_or_set

3.1.0 (2016-04-16)

  • 修改自动续订,如果锁被垃圾回收,则自动停止续订线程。由 Andrew Pashkin 在 33 中贡献。

3.0.0 (2016-01-16)

  • 修改了 release,使其立即过期信号键。由 Andrew Pashkin 在 28 中贡献。

  • 重置锁(resetreset_all)将释放锁。如果有其他人正在等待重置锁,它将获取该锁。由 Andrew Pashkin 在 29 中贡献。

  • Lock 对象上添加了 extend 方法。由 Andrew Pashkin 在 24 中贡献。

  • release 方法上改进了文档。由 Andrew Pashkin 在 22 中贡献。

  • 当使用 expire 选项时,修复了 acquire(block=True) 的处理(它不会无限期地阻塞)。由 Tero Vuotila 在 35 中贡献。

  • release 修改为检查是否使用相同 id 获取了锁。如果不是,将引发 NotAcquired。之前只是检查是否使用相同的实例(self._held)获取了锁。向后不兼容

  • release 中移除了 force 选项——它实际上并不必要,而且只会鼓励马虎编程。见 25向后不兼容

  • 取消了 Python 2.6 的测试。它可能可以工作,但它不受支持。

2.3.0 (2015-09-27)

  • 添加了 timeout 选项。由 Victor Torres 在 20 中贡献。

2.2.0 (2015-08-19)

  • 添加了 auto_renewal 选项。由 Nick Groenen 在 18 中贡献。

2.1.0 (2015-03-12)

  • 添加了新的特定异常类: AlreadyAcquiredNotAcquired

  • 当使用非等待获取时,略微提高了效率。

2.0.0 (2014-12-29)

  • Lock.token 重命名为 Lock.id。现在只能通过构造函数设置。由 Jardel Weyrich 在 11 中贡献。

1.0.0 (2014-12-23)

  • 修复了 Django 集成。(由 Jardel Weyrich 报告)

  • 重新组织测试以使用 py.test。

  • 添加了 Django 集成的测试。

  • 添加了 reset_all 功能。由 Yokotoka 在 7 中贡献。

  • 添加了 Lock.reset 功能。

  • 公开了 Lock.token 属性。

0.1.2 (2013-11-05)

  • ?

0.1.1 (2013-10-26)

  • ?

0.1.0 (2013-10-26)

  • ?

0.0.1 (2013-10-25)

  • PyPI 上的首次发布。

项目详细信息


下载文件

下载您平台上的文件。如果您不确定选择哪个,请了解更多关于 安装包 的信息。

源分发

python-redis-lock-4.0.0.tar.gz (162.5 kB 查看哈希值

上传时间

构建分发

python_redis_lock-4.0.0-py3-none-any.whl (12.2 kB 查看哈希值

上传时间 Python 3

由以下赞助

AWS AWS 云计算和安全赞助商 Datadog Datadog 监控 Fastly Fastly CDN Google Google 下载分析 Microsoft Microsoft PSF 赞助商 Pingdom Pingdom 监控 Sentry Sentry 错误记录 StatusPage StatusPage 状态页面