DEV Community

Lucas Barret
Lucas Barret

Posted on

Playing with Redis and Rails

Computer Science is hard, but let's make it funnier. In this article, I want to explore technologies and play with them without always having a structure to it.

This article is one of these. I will share my thoughts and idea, playing along with Redis and Ruby, Like I said less structured and maybe comments or deep dive, but I had a lot of fun writing and playing with this.

Delete key by pattern Redis

Recently, I encountered the issue of deleting keys in a Redis instance that is used as a cache. At this moment, I had not used the ruby/redis API.

Unfortunately, I had to retrieve all the keys manually and delete them since Redis itself does not have a pattern matching on delete. So you have to delete your keys one by one.

redis-cli 
127.0.0.1:6379> keys myk*
1) "myked"
2) "mykey"
127.0.0.1:6379> del myk* // not working
(integer) 0
127.0.0.1:6379> del mykey
(integer) 1
Enter fullscreen mode Exit fullscreen mode

If you use ruby, the ruby/redis API solves this issue. You have several ways to do it :

  1. Use redis.keys(pattern), which is strongly discouraged because of poor performance, and then do a map against your list of keys and delete them.
  2. Use redis.scan_each(match: pattern), that does not exists in Redis itself. And as we the precedent method, you map against your list and do whatever you want.
require "redis"

redis = Redis.new(host: 'localhost')

## discouraged because of poor performance
redis.keys("myk*").map do |s|
  p redis.get(s)
end

## Use this instead
redis.scan_each(match: 'myk*') do |name| ## encourage
  p redis.get(name)
end
Enter fullscreen mode Exit fullscreen mode

Use transactions in Redis

If you have used a database, you will likely have heard of a transaction. These are used to ensure the ACID principles.

The transaction ensures that when you run it, all the changement you did occur or none of them. This ensures that you are always in a consistent state in your database.

You can run them in Redis too in multiple ways:
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

Create a simple queueing jobs

This was the funniest part for me. You may know Sidekiq, an asynchronous job queuing system.

To run Sidekiq, you need Redis to queue all your jobs and then retrieve and run them.
This is not using the Pub/Sub mechanism of Redis.

So I created a queuing system and asynchronous job runner with this mechanism.

Let's do it!

First, I create a rails app only; I will call it frontkiq!

rails new frontkiq
Enter fullscreen mode Exit fullscreen mode

Once done, I decided to do something simple, create a model.

rails g model User name:string
Enter fullscreen mode Exit fullscreen mode

And then the fun begins:

I went to the lib directory and created two files. In the first one, we will call it queue_subs.rb. I have made a subscriber to my queue on two different channels.

The first is created, where you create a User, and the other is found, where you find a 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

Then you run your queueing system with the:

rails runner ./queue.rb
Enter fullscreen mode Exit fullscreen mode

And now, if you pop up an irb console, for example, you can play along with :

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

You have in your rails runner terminal :

#<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

Of course this will not replace Sidekiq or any queuing system. No retry mechanisms, never ensure that you job is ran. But it is funny to discover technologies and

Conclusion

I had a lot of fun writing this article. I hope you have learned some stuff. Not much to say except, keep learning and enjoy programming.

See you for next article ! :D

Top comments (0)