使用数据库作为任务队列

时间:2018-04-29 15:13:25

标签: java postgresql

在我们的一个java应用程序(基于postgresql db)中,我们有一个数据库表,用于维护要执行的任务列表。 每行都有一个json blob,用于任务的详细信息以及预定的时间值。

我们有一些java工作者/线程,其工作是搜索准备执行的任务(基于其计划值),从表中执行和删除它们。执行任务可能需要几秒钟。

问题是,多个工作人员可能会占用同一行,从而导致重复执行任务,这是我们想要避免的。

一种方法是,在执行select抓取一行时,使用FOR UPDATE执行此操作以锁定该行,从而阻止其他工作人员抓住锁定的同一行。

我对这种方法的关注是,只有在db中执行select事务时才会锁定行(根据this),而java代码实际上是在执行行/任务选择了,锁定已经消失,另一个工人可以再次抓住它。

有些人可以了解上述方法是否可行吗?谢谢!

2 个答案:

答案 0 :(得分:0)

将DB调用视为原子指令并在表周围设计无锁算法,使用更新将“正在进行”的布尔列从false更改为true。也可能只是state int(0 =有效,1 =进行中,N =结果代码)。

确保您在状态0上有一个部分索引(可能还有1个从崩溃中恢复以查找正在进行的任务),因此...where state=0仍然具有选择性和快速性(在预定的时间索引之上) )。

希望这有帮助。

答案 1 :(得分:0)

当一个线程成功锁定给定连接上的行时,另一个尝试获取另一个连接上的行的锁定应该失败。您应该使用某种 no-wait 子句发出select-for-update,以便在行被锁定时立即请求失败。

现在,这不能解决查询vs锁定竞争,因为失败的锁定可能会中断线程的执行。您可以通过(在每次执行中)解决这个问题:

  1. 选择包含新任务的所有记录(无论是否正在处理)
  2. 对于[1]中返回的每个新任务,运行匹配的select-for-update,然后在锁定失败时继续处理任务。
  3. 如果任何锁定尝试失败,请跳过该任务而不会使整个过程失败。