🦔
redis で key pattern にマッチしたものを pop する
redis で key pattern にマッチしたものを pop する
redis を job queue っぽく使いたくて雑に調べてたら GETDEL ってのがあってめっちゃ便利!やっぱ redis いいね!なんて思ってたら、どうやら最近追加されたコマンドらしく since 6.2 から使えるらしい。
んで、本番環境は AWS ElastiCache なので使えるバージョン調べてみたら最新は 6.x ってなってて、ものっそいびみょーなので実際起動してみたら 6.0.5 が起動した。あかんやんか!
GET と DEL 組み合わせたらできなくはないんだけども、複数プロセスから処理が走るためにアトミックに処理できないのはつらい。
ほんじゃここはひとつ lua 書いて redis に食わせるかー。どうせならついでに KEYS もからませて key pattern にマッチするものから適当にひとつ pop するようにしてやろう。
って事で書いたものがコチラ
--
-- popkey.lua
--
local keys = redis.call("KEYS", KEYS[1])
-- 要素数 0 なら nil でおしまい
if #keys == 0 then
redis.log(redis.LOG_VERBOSE, "POPKEY: can't find any keys.")
return nil
end
-- 最初の要素のキーを抜き出す
local key = keys[1]
-- 要素を取り出してキーを削除
local data = redis.call("GET", key)
redis.call("DEL", key)
redis.log(redis.LOG_VERBOSE, "POPKEY: found key '"..key.."'")
return data
特別トリッキーなことは何もしてなくて、考えてたことをそのまま lua で書いてアトミック性を確保しただけっていう。
これを EVAL とか EVALSHA で実行すると key pattern にマッチするものがなければ nil が返るしあればその value が返ってくる。
ここまでやってみて、これもっと簡単にできる方法あるんじゃないの?って思ってさらに調べてみたら案の定あった。 ZADD で入れて ZPOPMIN で取り出したらできるわ。しかも score をタイムスタンプ指定したら(ほぼほぼ)順番まで保証されるわ。ぐうのねもでない。
ということで、車輪の再発明の劣化版みたいなことをやってしまったわけですが、ひさびさに lua 書けて頭の体操にはなったのでヨシとする。
Discussion