2

在我的应用程序中,有一个批处理机制。它(理论上)在 redis 列表中累积项目,然后一次处理所有项目并清理(如有必要)。这是代码:

def with_private_key redis, name
  return unless redis.exists name

  # atomically rename to a random name, so that the batch isn't appended to.
  tmpname = "temp:#{SecureRandom.hex}"
  redis.rename name, tmpname

  # get batch elements
  batch = redis.lrange(tmpname, 0, -1).map{|b| JSON.parse(b) }

  begin
    # actually do something with the batch
    yield batch
  rescue => ex
    # revert and give up
    redis.rename tmpname, name
    raise
  else
    # if there was no exception - drop the temp key, it's not needed anymore
    redis.del tmpname
  end
end

这是这个实现的一个小问题:有时临时键不会被删除并保留在数据库中。当我撰写这个问题时,我意识到反向重命名可能会失败,因为已经创建了新的密钥和新的批次。

那么,我应该如何改进这个算法呢?

  • 就地修改批处理不起作用。LRANGE + LTRIM 对不是原子的。
  • 定期检查临时键并尝试重新处理它们(命名公式必须更改为包含app_id,但这在这里可能并不重要)。
  • 还要别的吗?也许一些 Lua 技巧(还没有使用 Lua)?

编辑:

我看到我关于重命名的理论是无效的。重命名命令

将 key 重命名为 newkey。当源名称和目标名称相同或 key 不存在时,它会返回错误。如果 newkey 已经存在,它将被覆盖。

4

1 回答 1

0

我会尝试

batch, _ = redis.multi do |r|
  r.lrange name, 0, -1
  r.ltrim name, 0, -1
end

如果客户端在获取批次并修剪列表后崩溃,则可能会丢失批次。

于 2012-12-27T05:31:11.253 回答