【发布时间】:2021-04-21 13:06:02
【问题描述】:
假设我们有一个要执行的任务列表和一些从该列表中弹出项目的工作人员。 如果工作人员在完成任务执行之前意外崩溃,则该任务将丢失。 什么样的机制可以防止这种情况发生,以便我们可以重新处理废弃的任务?
【问题讨论】:
-
你在使用 Redis Streams 吗?
-
不,我不是。使用列表。
假设我们有一个要执行的任务列表和一些从该列表中弹出项目的工作人员。 如果工作人员在完成任务执行之前意外崩溃,则该任务将丢失。 什么样的机制可以防止这种情况发生,以便我们可以重新处理废弃的任务?
【问题讨论】:
你需要使用 ZSET 来解决这个问题
弹出操作
确认操作
工人
您需要运行一个调度的工作程序,如果它们过期,它将把项目从 ZSET 移动到列表
详细阅读,我在Rqueue中是怎么做的https://medium.com/@sonus21/introducing-rqueue-redis-queue-d344f5c36e1b
Github 代码:https://github.com/sonus21/rqueue
【讨论】:
set 或 zset 成员没有EXPIRE,并且没有从 zset 弹出并推送到列表的原子操作。所以我写完了这个原子运行的 lua 脚本。
首先我向executing-tasks zset 添加一个带有时间戳分数的任务((new Date()).valueOf() in javascript):
ZADD 1619028226766 executing-tasks
然后我运行脚本:
EVAL [THE SCRIPT] 2 executing-tasks tasks 1619028196766
如果任务超过 30 秒,它将被发送到tasks 列表。如果没有,它将被发送回executing-taskszset。
这是脚本
local source = KEYS[1]
local destination = KEYS[2]
local min_score = ARGV[1]
local popped = redis.call('zpopmin', source)
local id = popped[1]
local score = popped[2]
if table.getn(popped) > 0 then
if score < min_score then
redis.call('rpush', destination, id)
return { "RESTORED", id }
else
redis.call('zadd', source, score, id)
return { "SENT_BACK", id }
end
end
return { "NOTHING_DONE" }
【讨论】: