1
0
Fork 0
mirror of https://github.com/mperham/sidekiq.git synced 2022-11-09 13:52:34 -05:00
mperham--sidekiq/lib/sidekiq/rails.rb
Eugene Kenny f49b4f11db Use Rails executor if code reloading is disabled (#3221)
We have to release the current thread's Active Record connection after
performing each job, in case another thread is waiting to use it.

On Rails 4 and earlier, this is handled with middleware. On Rails 5 in
development mode, the reloader does it by delegating to the executor.
However on Rails 5 in production mode, we're not adding the middleware
or enabling the reloader, so connections will never be released.

We can call the executor directly to have it release the connection for
us in this case. By calling it inside the middleware stack, the job will
be retried if the executor raises, avoiding the problem with lost jobs
that led to the reloader being disabled in production.
2016-11-12 09:17:36 -05:00

110 lines
3.7 KiB
Ruby

# frozen_string_literal: true
module Sidekiq
def self.hook_rails!
return if defined?(@delay_removed)
ActiveSupport.on_load(:active_record) do
include Sidekiq::Extensions::ActiveRecord
end
ActiveSupport.on_load(:action_mailer) do
extend Sidekiq::Extensions::ActionMailer
end
Module.__send__(:include, Sidekiq::Extensions::Klass)
end
# Removes the generic aliases which MAY clash with names of already
# created methods by other applications. The methods `sidekiq_delay`,
# `sidekiq_delay_for` and `sidekiq_delay_until` can be used instead.
def self.remove_delay!
@delay_removed = true
[Extensions::ActiveRecord,
Extensions::ActionMailer,
Extensions::Klass].each do |mod|
mod.module_eval do
remove_method :delay if respond_to?(:delay)
remove_method :delay_for if respond_to?(:delay_for)
remove_method :delay_until if respond_to?(:delay_until)
end
end
end
class Rails < ::Rails::Engine
# We need to setup this up before any application configuration which might
# change Sidekiq middleware.
#
# This hook happens after `Rails::Application` is inherited within
# config/application.rb and before config is touched, usually within the
# class block. Definitely before config/environments/*.rb and
# config/initializers/*.rb.
config.before_configuration do
if ::Rails::VERSION::MAJOR < 5 && defined?(::ActiveRecord)
Sidekiq.server_middleware do |chain|
require 'sidekiq/middleware/server/active_record'
chain.add Sidekiq::Middleware::Server::ActiveRecord
end
end
end
initializer 'sidekiq' do
Sidekiq.hook_rails!
end
# We have to add the reloader after initialize to see if cache_classes has
# been turned on.
#
# This hook happens after all initialziers are run, just before returning
# from config/environment.rb back to sidekiq/cli.rb.
config.after_initialize do
if ::Rails::VERSION::MAJOR >= 5
# The reloader also takes care of ActiveRecord but is incompatible with
# the ActiveRecord middleware so make sure it's not in the chain already.
if defined?(Sidekiq::Middleware::Server::ActiveRecord) && Sidekiq.server_middleware.exists?(Sidekiq::Middleware::Server::ActiveRecord)
raise ArgumentError, "You are using the Sidekiq ActiveRecord middleware and the new Rails 5 reloader which are incompatible. Please remove the ActiveRecord middleware from your Sidekiq middleware configuration."
elsif ::Rails.application.config.cache_classes
# The reloader API has proven to be troublesome under load in production.
# We won't use it at all when classes are cached, see #3154
Sidekiq.logger.debug { "Autoload disabled in #{::Rails.env}, Sidekiq will not reload changed classes" }
Sidekiq.options[:executor] = Sidekiq::Rails::Executor.new
else
Sidekiq.logger.debug { "Enabling Rails 5+ live code reloading, so hot!" }
Sidekiq.options[:reloader] = Sidekiq::Rails::Reloader.new
end
end
end
class Executor
def initialize(app = ::Rails.application)
@app = app
end
def call
@app.executor.wrap do
yield
end
end
def inspect
"#<Sidekiq::Rails::Executor @app=#{@app.class.name}>"
end
end
class Reloader
def initialize(app = ::Rails.application)
@app = app
end
def call
@app.reloader.wrap do
yield
end
end
def inspect
"#<Sidekiq::Rails::Reloader @app=#{@app.class.name}>"
end
end
end if defined?(::Rails)
end