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.
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
If you use ruby, the ruby/redis API solves this issue. You have several ways to do it :
redis.keys(pattern), which is strongly discouraged because of poor performance, and then do a map against your list of keys and delete them.
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
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:
TOCHANGE redis.multi do |multi| multi.set("key", "value") multi.incr("counter") end # => ["OK", 6]
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
Once done, I decided to do something simple, create a model.
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.
##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:
rails runner ./queue.rb
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>
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">
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
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