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 で動作していません)?

編集:

名前の変更に関する私の理論は無効であることがわかりました。RENAME コマンド:

キーの名前を newkey に変更します。ソース名とデスティネーション名が同じ場合、またはキーが存在しない場合はエラーを返します。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 に答える