使用PostgreSQL顾问锁轻松实现分布式锁定。

PALs的Python项目详细描述


https://circleci.com/gh/level12/pals.svg?style=shieldhttps://codecov.io/gh/level12/pals/branch/master/graph/badge.svg

简介

pals使使用PostgreSQL Advisory Locks来做分布式应用程序级别变得很容易 锁定。

不要将这种类型的锁定与postgresql中的表或行锁定混淆。不一样了 事情。

使用redis、memcache、zeromq和 其他人。但是对于那些已经在使用postgresql的用户来说,另一个服务的设置和管理是 没必要。

用法

# 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 worksassertlock1.acquire()isTrue# Non blocking version should fail immediatelyassertlock2.acquire(blocking=False)isFalse# Blocking version will retry and eventually failacquired,retries=lock2.acquire(return_retries=True)assertacquiredisFalseassertretries>4# You can set the retry parameters yourself if you don't like our defaults.lock2.acquire(retry_delay=100,retry_timeout=300)# They can also be set on the lock instancelock3=locker.lock('my-lock',retry_delay=100,retry_timeout=300)# Release the locklock1.release()# Recommended usage pattern:ifnotlock1.acquire():# Remember to check to make sure you got your lockreturntry:# do my work herefinally:lock1.release()# But more recommended and easier is to use the lock as a context manager:withlock1:assertlock2.acquire()isFalse# Outside the context manager the lock should have been released and we can get it nowassertlock2.acquire()# The context manager version will throw an exception if it fails to acquire the lock.  This# pattern was chosen because it feels symantically wrong to have to check to see if the lock# was actually acquired inside the context manager.  If the code inside is ran, the lock was# acquired.try:withlock1:# We won't get here because lock2 acquires the lock just abovepassexceptpals.AcquireFailure:pass

在本地运行测试

设置数据库连接

我们提供了docker compose文件,但您不必使用它:

$ docker-compose up -d
$ export PALS_DB_URL=postgresql://postgres:password@localhost:54321/postgres

您还可以将环境变量放在.env文件中,pipenv将接收它。

运行测试

含毒物:

$ tox

或者,手动:

$ pipenv install --dev
$ pipenv shell
$ pytest pals/tests.py

解除锁定和过期

与建立在memcache和redis等缓存服务上的锁定系统不同,它们的密钥可以过期 通过该服务,postgresql中没有过期咨询锁的能力。如果客户 持有一个锁,然后睡眠/挂起分钟/小时/天,没有其他客户能够得到 锁定,直到客户端释放它。这对我们来说是件好事,如果锁是 获得后,应该一直保存到释放。

但是,万一锁不开怎么办?

  1. 如果开发人员使用lock.acquire(),但以后不调用lock.release()
  2. 如果锁中的代码意外抛出异常(并且.release()未被调用)?
  3. 如果运行应用程序的进程崩溃或进程的服务器死机?

好友以几种不同的方式帮助上面的1和2:

  • 锁作为上下文管理器工作。尽可能多地使用它们以确保锁被释放。
  • 垃圾收集时锁会释放锁。
  • pals使用专用的sqlalchemy连接池。当连接返回到池时, 要么是因为调用了连接.close(),要么是因为对连接进行了垃圾收集, pals发出apg_advisory_unlock_all()。因此,一个无所事事的人是不可能的 池中的连接始终保持锁定。

关于上面的3,pg_advisory_unlock_all()被postgresql隐式调用,只要 连接(也称为会话)结束,即使客户端断开连接不正常。所以如果一个过程 崩溃或以其他方式消失,postgresql应该注意并移除所有由它持有的锁 连接/会话。

可能存在PostgreSQL没有检测到连接已关闭并保持不变的可能性。 无限期打开的锁。然而,在使用scripts/hang.py的手动测试中,没有找到任何方法 在postgresql没有检测到的情况下结束python进程。

更改日志

0.2.0发布日期:2019-03-07

  • 修正“acquire”(737763f)的拼写错误

0.1.0发布日期:2019-02-22

  • 使用lock_timeout设置终止阻塞调用(d0216ce
  • 固定毒性(1b0ffe2
  • 重命名为pals(95d5a3c
  • 改进自述文件(e8dd6f2
  • 将测试文件移动到更好的位置(a153af5
  • 添加flake8 dep(3909c95
  • 修复测试,以便它们也在本地工作(7102294
  • 使电路工作(28f16d2
  • 禁止锁中的异常(e29c1ce
  • 添加hang.py脚本(3372ef0
  • 修复打包内容,更新自述文件(cebd976
  • 初始提交(871b877

欢迎加入QQ群-->: 979659372 Python中文网_新手群

推荐PyPI第三方库


热门话题
文件名的java正则表达式限制名称大小和文件扩展名   Mac上的java Android SDK:jspawnhelper意外退出   java SQL Server 2000到Oracle 12c重音字符   在Java中快速比较大数据集中的值和小数据集中的值   java在代码中的许多地方保留对对象的引用   Java规范中私有内部类的jvm访问标志与反射API不一致?   比较2个int数组中匹配的数字   java Apache Commons数学简化回归:get prediction stderr   安卓 Java SDK管理器因命令行输出中的“flashplayerplugin”而崩溃   JavaSQLite:关闭DB时必须关闭游标吗?   泛型Java设计抽象类声明示例说明   java应用程序在添加片段时崩溃   如何在java中使用注释为字段加载值