はじめに
RailsでRedisを使うために挙動を確認しました。
Railsで使ってはいるのですが、薄めのラッパー関数でRedisのコマンドをほぼそのまま呼び出すだけなので、Redisに直接実行してるのと変わらないかと思います。
Redisはdockerで動かしています。
バージョン
- Redis: v7.2
- Rails: v7.0
- redis-client(gem): v0.22.2
初期化
initializerでredisインスタンスを作ります。
redis_config = RedisClient.config(host: "redis", port: 6379, db: 1)
REDIS_DATA_STORE = redis_config.new_pool(timeout: 3, size: Integer(ENV.fetch("RAILS_MAX_THREADS", 5)))
基本構文
pry(main)> REDIS_DATA_STORE.call("SET", "id1", "some value")
=> "OK"
pry(main)> REDIS_DATA_STORE.call("GET", "id1")
=> "some value"
ハッシュ
基本的な使い方
pry(main)> hash1 = { "key1" => "value1", "key2" => "value2" }
=> {"key1"=>"value1", "key2"=>"value2"}
pry(main)> REDIS_DATA_STORE.call("HSET", "hid1", hash1)
=> 2
pry(main)> REDIS_DATA_STORE.call("HGETALL", "hid1")
=> {"key1"=>"value1", "key2"=>"value2"}
キーにシンボル使った場合、自動でstringのキーになる。
pry(main)> hash2 = { key1: "value1", key2: "value2" }
=> {:key1=>"value1", :key2=>"value2"}
pry(main)> REDIS_DATA_STORE.call("HSET", "hid2", hash2)
=> 2
pry(main)> REDIS_DATA_STORE.call("HGETALL", "hid2")
=> {"key1"=>"value1", "key2"=>"value2"}
一部を指定すれば、一部だけ更新される。
pry(main)> REDIS_DATA_STORE.call("HSET", "hid1", {"key1" => "new value1"})
=> 0
pry(main)> REDIS_DATA_STORE.call("HGETALL", "hid1")
=> {"key1"=>"new value1", "key2"=>"value2"}
ハッシュの中にハッシュは入れられない。
リストも同様に使えないので、使いたい場合はjsonにしてstringとして保存するか、内側のハッシュを別のキーで保存して、そのキーをトップのハッシュのvalueに保存する。
pry(main)> sub_hash = { subkey1: "sub value" }
=> {:subkey1=>"sub value"}
pry(main)> main_hash = { key1: "value1", key2: sub_hash }
=> {:key1=>"value1", :key2=>{:subkey1=>"sub value"}}
pry(main)> REDIS_DATA_STORE.call("HSET", "hid3", main_hash)
TypeError: Unsupported command argument type: Hash
Expire
3秒後に消える設定をした場合
def expire_test
REDIS_DATA_STORE.call("SET", "expire_key1", "value1")
REDIS_DATA_STORE.call("EXPIRE", "expire_key1", 3)
4.times do |i|
p "#{i} sec passed"
p REDIS_DATA_STORE.call("GET", "expire_key1")
sleep 1
end
end
pry(main)> expire_test
"0 sec passed"
"value1"
"1 sec passed"
"value1"
"2 sec passed"
"value1"
"3 sec passed"
nil
途中でデータupdateした場合
EXPIREされないので、新たに設定が必要
def expire_test2
REDIS_DATA_STORE.call("SET", "expire_key1", "value1")
REDIS_DATA_STORE.call("EXPIRE", "expire_key1", 3)
8.times do |i|
p "#{i} sec passed"
p REDIS_DATA_STORE.call("GET", "expire_key1")
sleep 1
REDIS_DATA_STORE.call("SET", "expire_key1", "updated value1") if i == 1
end
end
pry(main)> expire_test2
"0 sec passed"
"value1"
"1 sec passed"
"value1"
"2 sec passed"
"updated value1"
"3 sec passed"
"updated value1"
"4 sec passed"
"updated value1"
"5 sec passed"
"updated value1"
"6 sec passed"
"updated value1"
"7 sec passed"
"updated value1"
ハッシュをupdateした場合
ハッシュをupdateした場合は、expireは更新されず、削除もされない。
def expire_test3
hash = { "key1" => "value1", "key2" => "value2" }
REDIS_DATA_STORE.call("HSET", "expire_key2", hash)
REDIS_DATA_STORE.call("EXPIRE", "expire_key2", 3)
5.times do |i|
p "#{i} sec passed"
p REDIS_DATA_STORE.call("HGETALL", "expire_key2")
sleep 1
REDIS_DATA_STORE.call("HSET", "expire_key2", {"key1": "updated value1"}) if i == 1
end
end
pry(main)> expire_test3
"0 sec passed"
{"key1"=>"value1", "key2"=>"value2"}
"1 sec passed"
{"key1"=>"value1", "key2"=>"value2"}
"2 sec passed"
{"key1"=>"updated value1", "key2"=>"value2"}
"3 sec passed"
{}
"4 sec passed"
{}
同じキーに違うデータタイプを割り当てる
違うタイプに同じキーは使えない。
pry(main)> REDIS_DATA_STORE.call("SET", "id4", "value4")
=> "OK"
pry(main)> REDIS_DATA_STORE.call("HSET", "id4", {"key4" => "hash value4"})
RedisClient::WrongTypeError: WRONGTYPE Operation against a key holding the wrong kind of value
まとめ
バージョンによって挙動が異なるかもしれないので、実験してみるのが大事です。