私のアプリには、バッチ処理メカニズムがあります。(理論的には) 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 が既に存在する場合は上書きされます。