How to separate Development and Production sidekiq workers - ruby-on-rails

I am running sidekiq on a production rails server, and some of its queues workers end up in my development sidekiq instance and, therefore, causes a bunch of errors. The same thing happens with my development sidekiq instance. When I'm in the development version of the application and I click something that kicks off a sidekiq worker, it sometimes tries to run it in the production sidekiq instance and the production database doesn't have the same information.
Is there a proper way to separate these queued jobs so that they only run in the instance which they are initiated?

Sidekiq uses Redis to store enqueued jobs. By default, all sidekiq instances will use the default Redis database. You can change this by creating an initializer in config/initializers/sidekiq.rb
if Rails.env == :production
redis_host = '127.0.0.1'
redis_port = 6379
redis_db = 1
else
redis_host = '127.0.0.1'
redis_port = 6379
redis_db = 2
end
Sidekiq.configure_server do |config|
config.redis = { url: "redis://#{redis_host}:#{redis_port}/#{redis_db}" }
end
Sidekiq.configure_client do |config|
config.redis = { url: "redis://#{redis_host}:#{redis_port}/#{redis_db}" }
end
And change redis_host, redis_port and redis_db with appropriate values. This way each environment will use a separate Redis database. Also don't forget to pass appropriate environment when starting a sidekiq instance with something like:
bundle exec sidekiq -e production

Related

Can one rail app use multiple Resque (in different engines) and multiple redis instances?

I have my rails app , where my different services are in different different engines .I want to use different resque (and different redis and different workers) for my different engines .How to do it in rails ?
Since you have not shared any code, I am not sure how you have structured your app and how are you using Redis and workers. Hence I will have to assume many things while answering this question.
Let's say your structure is like this
root
engines
engine1
app
config
...
engine2
app
config
...
You can keep resque config like this
resque1 config with redis running of localhost on port 6380
#root/engines/engine1/config/resque.yml
development: localhost:6379 #redis1
test: localhost:6379
...
resque2 config with redis running of localhost on port 6380
#root/engines/engine2/config/resque.yml
development: localhost:6380
test: localhost:6380
...
rescue1 initializer
#root/engines/engine1/config/initializers/resque.yml
rails_root = File.dirname(__FILE__) + '/../..'
rails_env = ENV['RAILS_ENV'] || 'development'
config_file = rails_root + '/engines/engine1/config/resque.yml'
resque_config = YAML::load(ERB.new(IO.read(config_file)).result)
Resque.redis = resque_config[rails_env]
rescue2 initializer
#root/engines/engine2/config/initializers/resque.yml
rails_root = File.dirname(__FILE__) + '/../..'
rails_env = ENV['RAILS_ENV'] || 'development'
config_file = rails_root + '/engines/engine2/config/resque.yml'
resque_config = YAML::load(ERB.new(IO.read(config_file)).result)
Resque.redis = resque_config[rails_env]
You can start workers like this
RAILS_ENV=production resque-web rails_root/engines/engine1/config/initializers/resque.rb
RAILS_ENV=production resque-web rails_root/engines/engine2/config/initializers/resque.rb
Also, If you want to use a single redis and resque instance then, for redis you can namespace it https://github.com/resque/redis-namespace
and for resque you can define different sets of queues for each engine.
You can use the same redis with different namesapces for each engine.
Or if memory of the redis is your concen, you can trying using redis connection pool gem.

Heroku: error for PostGIS column in web dyno but not in one-off or worker dynos

I've got the beginnings of a spatial app (PostGIS + Rails + RGeo) with a single line_string column on one of my models. On my local machine everything is good, the problem is on Heroku web dynos, where Rails/activerecord doesn't recognise the RGeo/PostGIS line_string type.
Each time after deploying, the first time the model is loaded I see the following in the logs:
app[web.1]: unknown OID 17059: failed to recognize type of 'line_string'. It will be treated as String.
Then if I add some logging to STDOUT I can see:
mymodel.line_string.class # String
RGeo::Feature::Geometry.check_type(mymodel.line_string) # false
However, if I run a one-off dyno with rails console (heroku run rails c production) everything is good. I see the output I expect:
irb(main):001:0> mymodel.line_string.class
=> RGeo::Geographic::SphericalLineStringImpl
irb(main):002:0> RGeo::Feature::Geometry.check_type(mymodel.line_string)
=> true
It's also ok under worker dynos.
What would cause the unknown OID error? Why would one-off and worker dynos be able to work with this column perfectly but the web dyno not?
Puma was starting without configuration for PostGIS that I had added in application.rb. ActiveRecord started working with PostGIS once I added the following to config/puma.rb:
on_worker_boot do
if defined?(ActiveRecord::Base)
config = ActiveRecord::Base.configurations[Rails.env] ||
Rails.application.config.database_configuration[Rails.env]
config['adapter'] = 'postgis'
ActiveRecord::Base.establish_connection(config)
end
end
on_restart do
if defined?(ActiveRecord::Base)
config = ActiveRecord::Base.configurations[Rails.env] ||
Rails.application.config.database_configuration[Rails.env]
config['adapter'] = 'postgis'
ActiveRecord::Base.establish_connection(config)
end
end
The other dyno types were just using application.rb so they were always configured correctly.

Sidekiq processing with local redis but not with remote

I have a RoR app with background jobs using whenever and sidekiq gems.
In development environment when I launch sidekiq with local redis instance (on localhost) the job keeps getting executed without problems. But when I switch to a remote redis instance (Heroku add-on) and restart sidekiq, it says it started processing, but nothing happens and workers aren't doing any jobs.
Here's my config/schedule.rb (for whenever gem)
every 2.minutes do
rake "crawler:crawl"
end
Here's my initializers/redis.rb:
Sidekiq.configure_server do |config|
config.redis = { :url => 'redis://user:pass#spinyfin.redistogo.com:9098/' }
end
Sidekiq.configure_client do |config|
config.redis = { :url => 'redis://user:pass#spinyfin.redistogo.com:9098/' }
end
If I comment out the content in redis.rb and run a local redis instance, the jobs are processed normally. But when I use this remote redis instance, this shows up and then nothing gets processed:
2013-11-29T15:09:26Z 95156 TID-ov6y7e14o INFO: Booting Sidekiq 2.13.0 using redis://redistogo:user#spinyfin.redistogo.com:9098/ with options {}
2013-11-29T15:09:26Z 95156 INFO: Running in ruby 1.9.3p327 (2012-11-10 revision 37606) [x86_64-darwin11.4.2]
2013-11-29T15:09:26Z 95156 INFO: See LICENSE and the LGPL-3.0 for licensing details.
2013-11-29T15:09:26Z 95156 INFO: Starting processing, hit Ctrl-C to stop
Maybe you connecting to wrong redis database or not connected at all.
In my apps I use redis url without trailing slash. In your case:
This is for database "0"
redis://user:pass#spinyfin.redistogo.com:9098
And this for database "1"
redis://user:pass#spinyfin.redistogo.com:9098/1
I use the environment variable REDIS_URL to ensure that everything is using the same Redis.
Re: Heroku - I just read this here as I was searching for my own solution:
If you're running on Heroku, you can't rely on the config/database.yml as that platform relies on the DATABASE_URL environment variable to determine the database connection configuration. Heroku overwrites the database.yml during slug compilation so that it reads from DATABASE_URL.

Sidekiq not connecting to Rails

I am having issues converting from Resque to Sidekiq. I'm not getting any errors though a perform_async(ids) doesn't add anything to Redis. I can add keys directly to the Redis server via the Redis.current.append("test", "key")
Also my Sidekiq worker connects to the Redis server, though I get an empty array when I ask for Sidekiq::Client.registered_workers The web UI shows only the skeleton with no information other than the Redis info. I don't know if this matters but Sidekiq.redis { |conn| conn.info } returns information that is all correct with my local Redis server. Though Sidekiq.server? returns a nil value.
Update: When I perform a perform_async(args) it returns a string.
It sounds like your Sidekiq configuration isn't using the same redis config for the client and server components of Sidekiq.
The client executes within your Rails app server, while the server is a stand-alone separate process where work is performed. If they both aren't using the same redis queue via the redis configuration, work will not be processed.
Here is an example config/initializers/sidekiq.rb config block using the same redis for both components:
redis = { url: (ENV['REDIS_URL'] || 'redis://127.0.0.1'), namespace: 'sidekiq' }
Sidekiq.configure_server do |config|
config.redis = redis
end
Sidekiq.configure_client do |config|
config.redis = redis
end
My guess is that you have a different namespace or configuration between your client and server config.
I was hitting the same issue.
Turns out I had rspec-sidekiq configured in my Gemfile's development group and rspec-sidekiq apparently stubs the async calls for testing.
The solution was amending my Gemfile as such:
gem 'rspec-sidekiq', group: :test, require: false
Finally, I added require 'rspec-sidekiq' in my spec_helper.rb.

Resque Not Selecting Correct Server From Config

I'm trying moving my Reddis server off to an external box. Have followed the Resque readme on github through.
In development mode, it loads the config just fine and connects to localhost on 6379:
resque.rb initialiser
rails_root = ENV['RAILS_ROOT'] || File.dirname(__FILE__) + '/../..'
rails_env = ENV['RAILS_ENV'] || 'development'
resque_config = YAML.load_file(rails_root + '/config/resque.yml')
Resque.redis = resque_config[rails_env]
resque.yaml
development: localhost:6379
playground: redis1.play.xxx.com:6379
production: redis1.pro.xxx.com:6379
However, in playground / production modes, it falls back to development server and doesn't connect. I'm assuming this is because unicorn's not declaring the environment correctly?
If I replace 'development' with 'playground' in the initialiser, it works.
I'm starting unicorn with:
unicorn -c config/unicorn.rb -E playground -l 8000 -D
How can I get it to pick up the correct conf??
Finally sorted although I don't really understand why... Won't accept my own answer for a couple of days if someone wants to interject.
By getting God to manage the service instead of starting / stopping manually, it picked up the correct environment.
Now I'm connecting to a remote redis service with no issues.

Resources