使用PostgreSQL咨询锁实现简单的分布式锁定。
项目描述
介绍
PALs使得使用PostgreSQL咨询锁进行分布式应用程序级锁定变得简单。
不要将此类锁定与PostgreSQL中的表或行锁定混淆。它们不是同一回事。
可以通过使用Redis、Memcache、ZeroMQ等方式实现分布式应用程序级锁定。但对于已经使用PostgreSQL的用户,设置和管理另一个服务是不必要的。
用法
安装
pip install PALs
然后使用方法如下
import datetime as dt
import pals
# Think of the Locker instance as a Lock factory.
locker = pals.Locker('my-app-name', 'postgresql://user:pass@server/dbname')
lock1 = locker.lock('my-lock')
lock2 = locker.lock('my-lock')
# The first acquire works
assert lock1.acquire() is True
# Non blocking version should fail immediately
assert lock2.acquire(blocking=False) is False
# Blocking version should fail after a short time
start = dt.datetime.now()
acquired = lock2.acquire(acquire_timeout=300)
waited_ms = duration(start)
assert acquired is False
assert waited_ms >= 300 and waited_ms < 350
# Release the lock
lock1.release()
# Non-blocking usage pattern
if not lock1.acquire(blocking=False):
# Aquire returned False, indicating we did not get the lock.
return
try:
# do your work here
finally:
lock1.release()
# If you want to block, you can use a context manager:
try:
with lock1:
# Do your work here
pass
except pals.AcquireFailure:
# This indicates the aquire_timeout was reached before the lock could be aquired.
pass
文档
只是这个readme文件、代码和测试。这是一个小型项目,应该很容易理解。
请随时提出问题。
本地运行测试
设置数据库连接
我们提供了一个docker-compose文件来简化测试的运行
$ docker-compose up -d $ export PALS_DB_URL=postgresql://postgres:password@localhost:54321/postgres
运行测试
使用tox
$ tox
或者,手动(假设已激活的虚拟环境)
$ pip install -e .[tests] $ pytest pals/tests/
锁定释放和过期
与建立在缓存服务(如Memcache和Redis)之上的锁定系统不同,这些服务的键可以被服务过期,PostgreSQL中没有过期建议锁的能力。如果一个客户端持有锁然后休眠/挂起几分钟/几小时/几天,没有其他客户端能获取那个锁,直到客户端释放它。这对我们来说实际上是一件好事,如果获取了锁,就应该保持直到释放。
但关于意外未释放锁的情况怎么办呢?
如果开发人员使用了
lock.acquire()
但没有随后调用lock.release()
呢?如果锁内的代码意外抛出异常(并且没有调用.release())?
如果运行应用程序的进程崩溃或进程的服务器关闭?
PALs以几种不同的方式帮助解决上述1和2中的问题。
锁作为上下文管理器工作。尽可能多地使用它们,以确保锁被释放。
锁在垃圾回收时释放其锁。
PALs使用专用的SQLAlchemy连接池。当连接返回到池中时,无论是由于调用
.close()
还是由于连接的垃圾回收,PALs都会发出pg_advisory_unlock_all()
。因此,空闲连接池中不应再保留任何持有的锁。
关于上述3,pg_advisory_unlock_all()
在连接(即会话)结束时被PostgreSQL隐式调用,即使客户端不优雅地断开连接。因此,如果一个进程崩溃或以其他方式消失,PostgreSQL应该注意到并删除该连接/会话持有的所有锁。
可能存在这样的情况:PostgreSQL没有检测到连接已关闭并无限期地保留锁。然而,在手动测试中使用scripts/hang.py
没有找到一种方法可以结束Python进程而不让PostgreSQL检测到。
另请参阅
更改日志
0.4.0发布于2024-04-16
0.3.5发布于2023-06-29
修复连接关闭后的游标使用(感谢@moser)(ded88e7)
0.3.4发布于2023-03-06
支持SQLAlchemy 2.0(《6879081》)
0.3.3发布于2023-01-06
向AcquireFailure异常添加附加信息(《6d81db9”)
0.3.2发布于2021-02-01
支持共享建议锁(感谢@absalon-james)(《ba2fe21”)
0.3.1发布于2020-09-03
0.3.0发布于2019-11-13
增强
项目清理
0.2.0版本发布于2019-03-07
修复“acquire”的拼写错误 (737763f)
0.1.0版本发布于2019-02-22
项目详情
下载文件
下载适合您平台的文件。如果您不确定选择哪个,请了解更多关于安装包的信息。