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がこの問題を解決します。方法はいくつかあります :

  1. 貧弱なパフォーマンスのために強く非推奨ですが、redis.keys(pattern) を使い、キーのリストに対してmapし、それらを削除します。
  2. 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