RedisとRailsで遊ぶ
コンピューターサイエンスは難しいけど、もっと楽しくしましょう。この記事では、いつも通りの構造に囚われずにテクノロジーを探求して遊んでみたいと思います。
これがその一つの記事です。RedisとRubyを使って遊びながら、私の考えやアイデアを共有します。構造が少なく、コメントや深掘りはあまりありませんが、書いて遊んでいてとても楽しかったです。
パターンでキーを削除するRedis
最近、キャッシュとして使っているRedisインスタンスの中でキーを削除する問題に遭遇しました。その時点で、私はruby/redis APIを使ったことがありませんでした。
残念ながら、Redis自体は削除時のパターンマッチング機能を備えていないため、手動で全てのキーを取得して削除する必要がありました。つまり、キーを一つ一つ削除するしかありません。
redis-cli
127.0.0.1:6379> keys myk*
1) "myked"
2) "mykey"
127.0.0.1:6379> del myk* // 動作しない
(integer) 0
127.0.0.1:6379> del mykey
(integer) 1
Enter fullscreen mode Exit fullscreen mode
Rubyを使っているなら、ruby/redis APIがこの問題を解決します。方法はいくつかあります :
- 貧弱なパフォーマンスのために強く非推奨ですが、
redis.keys(pattern)
を使い、キーのリストに対してmapし、それらを削除します。 - Redis自体にはない
redis.scan_each(match: pattern)
を使用します。そして、前の方法と同様、リストに対してmapし、好きなように処理します。
require "redis"
redis = Redis.new(host: 'localhost')
## パフォーマンスが悪いから非推奨
redis.keys("myk*").map do |s|
p redis.get(s)
end
## これを代わりに使う
redis.scan_each(match: 'myk*') do |name| ## 推奨される
p redis.get(name)
end
Enter fullscreen mode Exit fullscreen mode
Redisでトランザクションを使う
データベースを使用したことがあれば、トランザクションについて聞いたことがあるでしょう。これらはACID原則を保証するために使用されます。
トランザクションは、実行時に全ての変更が発生するか、一つも発生しないことを保証します。これによって、データベースが常に一貫した状態にあることを保証します。
Redisでも複数の方法で実行することができます:
https://redis.io/docs/manual/transactions/
TOCHANGE
redis.multi do |multi|
multi.set("key", "value")
multi.incr("counter")
end # => ["OK", 6]
Enter fullscreen mode Exit fullscreen mode
シンプルなキューイングジョブを作成する
これは私にとって最も面白い部分でした。あなたもSidekiqを知っているかもしれませんね、非同期ジョブキューシステムです。
Sidekiqを実行するには、Redisを使って全てのジョブをキューに入れてから、それを取り出して実行する必要があります。
これはRedisのPub/Subメカニズムを使ったものではありません。
そこで、私はこのメカニズムを使ってキューシステムと非同期ジョブランナーを作成しました。
さあ、やってみましょう!
まず、railsアプリを新たに作ります。あえてfrontkiqと名付けましょう!
rails new frontkiq
Enter fullscreen mode Exit fullscreen mode
一度完了したら、シンプルなことをすることに決めました。モデルを作成します。
rails g model User name:string
Enter fullscreen mode Exit fullscreen mode
そして楽しみが始まります:
libディレクトリに行き、二つのファイルを作成しました。最初のファイルをqueue_subs.rb
と呼びます。私はそこで、二つの別々のチャンネルで私のキューに購読者を作りました。
一つはUserを作成した時、もう一つはUserを検索した時です。
##lib/queue.rb
require "redis"
redis = Redis.new(host: 'localhost')
redis.subscribe(["create","find"]) do |on|
on.message do |channel,message|
if channel == "create"
User.create!(name: message)
end
if channel == "find"
p User.find_by(name: message)
end
User.create!(name: message)
end
end
Enter fullscreen mode Exit fullscreen mode
そして、次のようにキューシステムを実行します:
rails runner ./queue.rb
Enter fullscreen mode Exit fullscreen mode
そして今、例えばirbコンソールを開くと、次のように遊ぶことができます:
rails c
Loading development environment (Rails 7.0.6)
irb(main):001:0> require 'redis'
=> false
irb(main):002:0> redis = Redis.new
=> #<Redis client v4.8.1 for redis://127.0.0.1:6379/0>
irb(main):004:0> redis.publish('create','lucas')
=> 1
irb(main):005:0> redis.publish('find','lucas')
=> 1
irb(main):006:0>
Enter fullscreen mode Exit fullscreen mode
rails runnerターミナルには以下のように表示されます:
#<User id: 6, name: "lucas", created_at: "2023-07-06 16:23:08.066413000 +0000", updated_at: "2023-07-06 16:23:08.066413000 +0000">
Enter fullscreen mode Exit fullscreen mode
もちろんこれはSidekiqやその他のキューシステムの代わりにはなりません。リトライメカニズムはなく、ジョブが実行されたかを確証することもありません。しかし、技術を発見することは面白いものです。
結論
この記事を書くのはとても楽しかったです。何かを学んでいただけたら嬉しいです。言うことはあまりありませんが、学び続けてプログラミングを楽しんでください。
次の記事で会いましょう! :D
こちらの記事はdev.toの良い記事を日本人向けに翻訳しています。
https://dev.to/yet_anotherdev/playing-with-redis-and-rails-46i3