Playing with Redis and Rails
Tags: redis, rails, ruby
Published: 2023-08-01 05:04:49


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. 

```shell
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
```

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.

```ruby
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
```

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

```TO
TOCHANGE
redis.multi do |multi|
  multi.set("key", "value")
  multi.incr("counter")
end # => ["OK", 6]
```

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

```shell
rails new frontkiq
```

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

```shell
rails g model User name:string
```

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. 

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

Then you run your queueing system with the:

```shell
rails runner ./queue.rb
```

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

```shell
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>
```

You have in your rails runner terminal : 
```shell
#<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">
```

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