I have two Rails Apps that need to share some state. Each App needs to run background jobs during their execution lifetimes. I added Heroku Redis to each App, and Sidekiq. So when I run background jobs, everything is great.
I do not have shared state until I point one App’s REDIS_URL at the other Apps REDIS_URL and then both Apps are using the same shared Redis instance, I assume, and hence I have some shared state.
Now both Sidekiq instances share the same Redis, and one App is seeing the other Apps jobs and puking, because it has no idea about the other Apps jobs.
What is a clearer way of sharing state and keeping the jobs separate like they should be? I guess I need to just buy a cache I can use as shared state separate from the jobs?
Heroku App 1. Owns Redis Instance. Has Sidekiq. Runs Job AaaBbbJob
Heroku App 2. Points at Redis Instance from App1. Has Sidekiq
I notice the logs for App 2 show job AaaBbbJob tried running and failed as AaaBbbJob was not found.
In the logs of App 1, Job AaaBbbJob ran fine…
So my confusion lies in trying to assure myself that this is all OK. When App 1 through a job via Sidekiq into Redis, for whatever reason, App 2 saw that job in Redis too, and tried to run it.
So my question is, since throwing Jobs into Redis is now shared between two Apps, they both try and run ANY jobs they see?
2
Answers
You have two problems here :
For the first question, your 2 apps may have different Sidekiq Jobs but because of the same Redis instance, each of the Background app (which runs respective apps slug) pick all Sidekiq Jobs and only understand the jobs that they know about.
You can’t really help as Sidekiq is done like this. It is a feature that allows to run multiple dynos with Sidekiq for the same app.
What you can do to separate the two types of Sidekiq jobs is to assign a redis Database to each app : What's the Point of Multiple Redis Databases?
Redis can segregate data into 16 different databases.
For example my Redis config in one of my app is :
config/redis.yml
In another app I am using the database number 1. Then there is no collision.
The matching Sidekiq initializer looks like this then :
As you can see I am naming all redis clients (in development) on top of what I have explained. It is very useful to understand Redis clients consumption.
Regarding your second question: sharing "app state" I think it is about sharing global values such as constants or class variables.
It is probably possible to share this data through Redis but this is definitely ugly. You turn 2 apps a single monolith.
Even if you manage to do it properly, you have to rewrite everything when you want each app to have its own Redis instance.
The only way to do this is through a controller behaving as an API that would answer requests and deliver data to the other app.
Each app will need a Redis connection pool for the other Redis instance. Then App A can use those connections to send data or jobs to App B or push jobs to its sidekiq. Using multiple Redises is known as sharding.
https://github.com/mperham/sidekiq/wiki/Sharding