从不同的Postgres会话中锁定和解锁

时间:2016-10-22 21:53:50

标签: postgresql sqlalchemy locking

我有一个Postgres(9.5)DB,用于由Web和后台工作进程组成的应用程序。

如果我们收到HTTP请求POST /items/123/steps,那么Web应用程序将对后台任务进行排队,以对项目123执行“工作流程步骤”并返回。该项对应于Postgres items表中的一行,并且具有id值为123的列。

目标是以某种方式锁定项目123以进行处理,以便后续请求POST /items/123/steps将被拒绝,直到后台任务在完成其工作后解锁项目123。

同样,对GET /items/123的请求必须返回一个属性,指示项目123已被锁定,以便UI可以将项目显示为当前正在处理,直到后台任务解锁它。

因为在从队列中拾取后台任务之前可能会有延迟,所以后台任务在开始执行时锁定项目123是不够的。我希望将项目123从初始POST Web请求标记为已锁定,直到后台任务完成,以便在拾取后台任务之前,该项目显示为已锁定的任何Web请求。

如果可能的话,我想使用Postgres来实现这一目标。然而,我发现的选项似乎不起作用:

    事务结束时会释放
  • Row locks,这在我的Web处理程序返回时发生。后台任务在不同的事务中执行其工作。所以我不能对第123项进行SELECT FOR UPDATE
  • 会话级advisory lock越来越近了,除非我从Web进程中获取它,我无法从工作进程中解锁它,因为Web和工作进程都建立了自己的Postgres会话。

我可以通过实施临时锁定机制来解决这个问题:将locked列添加到items并在网络端点中将其设置为TRUE,然后再返回{{ 1}}在后​​台任务中。如果我更愿意采用更标准的方法,那么我宁愿这样做。

其他信息:这是一个Python项目,我正在使用SQLAlchemy从(Flask)Web应用程序和(Celery)后台任务访问Postgres。如果有另一种经过验证的方法可以使用这些适用于我的工具来实现目标。

1 个答案:

答案 0 :(得分:1)

使用locked列的“解决方法”实际上是正确的解决方案。

正如您所正确观察的那样,定期锁定和咨询都不能很好地适应您的情况。