diff --git a/lib/jobs.rb b/lib/jobs.rb index 37dc437dbd6..daaf1b18aac 100644 --- a/lib/jobs.rb +++ b/lib/jobs.rb @@ -61,11 +61,40 @@ module Jobs dbs.each do |db| begin - RailsMultisite::ConnectionManagement.establish_connection(db: db) - I18n.locale = SiteSetting.default_locale - execute(opts) - ensure - ActiveRecord::Base.connection_handler.clear_active_connections! + thread_exception = nil + # NOTE: This looks odd, in fact it looks crazy but there is a reason + # A bug in therubyracer means that under certain conditions running in a fiber + # can cause the whole v8 context to corrupt so much that it will hang sidekiq + # + # If you are brave and want to try to fix this either in celluloid or therubyracer, the repro is: + # + # 1. Create a big Discourse db: (you can start from script/profile_db_generator.rb) + # 2. Queue a ton of jobs, eg: User.pluck(:id).each{|id| Jobs.enqueue(:user_email, type: :digest, user_id: id)}; + # 3. Run sidekiq + # + # The issue only happens in Ruby 2.0 for some reason, you start getting V8::Error with no context + # + # See: https://github.com/cowboyd/therubyracer/issues/206 + # + # The restricted stack space of fibers opens a bunch of risks up, by avoiding them altogether + # we can mitigate giving up a very marginal amount of throughput + # + # Ideally we could just tell sidekiq to avoid fibers + + t = Thread.new do + begin + RailsMultisite::ConnectionManagement.establish_connection(db: db) + I18n.locale = SiteSetting.default_locale + execute(opts) + rescue => e + thread_exception = e + ensure + ActiveRecord::Base.connection_handler.clear_active_connections! + end + end + t.join + + raise thread_exception if thread_exception end end