首页 > 解决方案 > 使用 postgres 数据库锁定并发 cron

问题描述

我想要实现的是让同一应用程序的多个实例同时运行,但只有其中一个实例运行 cron,方法是将其锁定在 Postgres 数据库中。

到目前为止,我的解决方案是:

该解决方案有效,但我不确定 Postgres 是否存在另一种锁定机制,特别是不会让我执行产生错误的查询的机制。

标签: postgresqlconcurrencycron

解决方案


感谢@Belayer,我找到了一种使用咨询锁的好方法。

这是我的解决方案:

我的每个 cron 都有一个关联且唯一的 ID(整数格式)。所有的 crons 都在所有不同的服务器上启动。但在运行 cron 的主要功能之前,我尝试使用数据库中的唯一 ID 获取咨询锁。如果 cron 可以得到锁,那么它将运行 main 函数并释放锁,否则,它就停止。

如果您想用您选择的语言实现它,这里有一些伪代码:

enum Cron {
  Echo = 1,
  Test = 2
}

function uniqueCron(id, mainFunction) {
  result = POSTGRES ('SELECT pg_try_advisory_lock($id) AS "should_run"')
  if(result == FALSE){ return }

  mainFunction()

  POSTGRES ('SELECT pg_advisory_unlock($id)')
}

cron(* * * * *) do {
  uniqueCron(Cron.Echo, (echo "Unique cron"))
}

cron(*/5 * * * *) do {
  uniqueCron(Cron.Test, (echo "Test"))
}

多次运行这个过程,或者在许多不同的服务器上,都使用同一个数据库,将导致一次只执行一个 mainFunction,因为所有的 crons 都是同时启动的(不同服务器上的相同时间/时区)。如果一个服务器尝试获取锁而另一台服务器已经释放它,那么主函数太短而无法执行可能会导致问题。在这种情况下,请稍等片刻再释放锁。


推荐阅读