【问题标题】:Lock concurrent crons with postgres database使用 postgres 数据库锁定并发 cron
【发布时间】:2020-05-25 01:06:16
【问题描述】:

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

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

  • 在所有实例上运行 cron。
  • 在表 cron_lock 中插入一行,并带有 cron 的唯一标识符。
  • 如果我在运行插入查询时出错,很可能是因为该行已经存在(cron 标识符是表的主键)。如果是这样,我什么都不做,然后退出。
  • 如果我在运行插入查询时没有出错,那么应用程序实例将运行 cron 进程。
  • 在我的流程结束时,我删除了具有唯一标识符的行。

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

【问题讨论】:

  • 13.3.5. Advisory Locks9.26.10. Advisory Lock Functions。部分参考是 v12,如果您的版本不同,可能会有所不同。如果是这样,只需单击您的版本。
  • 如果进程在插入之后但在删除之前失败,会发生什么?在这种情况下你想发生什么?创建错误有什么问题?
  • @jjanes,为了避免锁永远存在,我会启动一个在所有实例上运行的 cron,删除超过某个时间之前创建的 cron_locks。而对于创建错误,它没有任何问题,除了它是一个错误,所以它会被记录,监控等......所以如果有一个“更清洁”的方式来做,我会更喜欢。跨度>
  • @Belayer 确实,这似乎是我想要的。我会看看我能不能用它做点什么!
  • 希望它对你有用。但请注意@jjanes 暗示警告。如果您获得了锁并且该过程随后失败,请确保您释放该锁。建议锁定在您释放它们之前一直有效。

标签: postgresql concurrency cron


【解决方案1】:

感谢@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 是同时启动的(不同的时间/时区在不同的服务器)。如果一个服务器尝试获取锁而另一台服务器已经释放它,那么主函数太短而无法执行可能会导致问题。在这种情况下,请稍等片刻再释放锁。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-12-23
    • 1970-01-01
    • 1970-01-01
    • 2021-07-27
    • 2018-03-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多