【发布时间】:2016-10-23 20:28:09
【问题描述】:
我有一个 Postgres (9.5) 数据库,用于由 Web 和后台工作进程组成的应用程序。
如果我们收到 HTTP 请求 POST /items/123/steps,那么 Web 应用程序会将后台任务排队,以在项目 123 上执行“工作流程步骤”并返回。该项目对应于 Postgres items 表中的一行,并有一个 id 值为 123 的列。
目标是以某种方式锁定项目 123 以进行处理,以便后续对 POST /items/123/steps 的请求将被拒绝,直到后台任务在完成其工作后解锁项目 123。
类似地,对GET /items/123 的请求必须返回一个属性,指示项目 123 已被锁定,以便 UI 可以将项目显示为当前正在处理,直到后台任务将其解锁。
因为在后台任务从队列中取出之前可能会有延迟,所以后台任务在开始执行时锁定项目 123 是不够的。我希望从最初的 POST Web 请求到后台任务完成之前将项目 123 标记为已锁定,以便在获取后台任务之前进入的任何 Web 请求,该项目都显示为已锁定。
如果可能的话,我想使用 Postgres 来完成这项工作。但是我发现的选项似乎不起作用:
-
Row locks 在事务结束时被释放,这发生在我的 web 处理程序返回时。后台任务在不同的事务中执行其工作。所以我不能在第 123 项上使用
SELECT FOR UPDATE。 - 会话级别的advisory lock 越来越接近,但如果我从 Web 进程获取它,我无法从工作进程中解锁它,因为 Web 和工作进程各自建立自己的 Postgres 会话。
我可以通过实现临时锁定机制来解决此问题:将locked 列添加到items 并在Web 端点中将其设置为TRUE,然后在后台任务中返回FALSE。如果存在更标准的方法,但我宁愿这样做。
附加信息:这是一个 Python 项目,我正在使用 SQLAlchemy 从(Flask)网络应用程序和(Celery)后台任务访问 Postgres。如果有另一种行之有效的方法可以使用这些适合我的工具来实现目标。
【问题讨论】:
标签: postgresql sqlalchemy locking