rails-on-services / apartment

Database multi-tenancy for Rack (and Rails) applications
376 stars 148 forks source link

Tenant is not switched in Active Job #102

Open holidayworking opened 4 years ago

holidayworking commented 4 years ago

Steps to reproduce

I need to run a job like the one below for each tenant.

class ReviewNotificationJob < ApplicationJob
  queue_as :default

  def perform(review)
    Rails.logger.debug "Thank you your review - #{review.comment}"
  end
end

Therefore, config/initializers/active_job.rb is as follows.

class ActiveJob::Base
  class << self
    def execute(job_data)
      Apartment::Tenant.switch(job_data['tenant']) do
        super
      end
    end
  end

  def serialize
    super.merge('tenant' => Apartment::Tenant.current)
  end
end

I created a sample app to report this issue. If you execute the following with this app, it will be reproduced.

company = Company.create(name: 'Company 1', tenant_name: 'company1')
Apartment::Tenant.create(company.tenant_name)
Apartment::Tenant.switch!(company.tenant_name)
review = Review.create(comment: 'test')
ReviewNotificationJob.perform_later(review)

Expected behavior

A tenant is switched in Active Job.

Actual behavior

The following is output to the log/development.log, and it seems that a tenant is not switched.

[ActiveJob] Enqueued ReviewNotificationJob (Job ID: 721907ae-98b4-4380-bc5c-9751259b4fa7) to Resque(default) with arguments: #<GlobalID:0x000055a164a78d10 @uri=#<URI::GID gid://app/Review/1>>
     (0.9ms) SET NAMES utf8mb4,  @@SESSION.sql_mode = CONCAT(CONCAT(@@sql_mode, ',STRICT_ALL_TABLES'), ',NO_AUTO_VALUE_ON_ZERO'),  @@SESSION.sql_auto_is_null = 0, @@SESSION.wait_timeout = 2147483  []
  ↳ config/initializers/active_job.rb:4:in `execute'
     (0.5ms) use `app_development`  []
  ↳ config/initializers/active_job.rb:4:in `execute'
     (0.5ms) use `app_development`  []
  ↳ config/initializers/active_job.rb:4:in `execute'
     (0.3ms) use `company1`  []
  ↳ config/initializers/active_job.rb:4:in `execute'
     (0.3ms) use `app_development`  []
  ↳ config/initializers/active_job.rb:5:in `block in execute'
    Review Load (0.5ms) SELECT `reviews`.* FROM `reviews` WHERE `reviews`.`id` = 1 LIMIT 1  []
  ↳ config/initializers/active_job.rb:5:in `block in execute'
     (0.3ms) use `app_development`  []
  ↳ config/initializers/active_job.rb:4:in `execute'

System configuration

rpbaltazar commented 4 years ago

Thank you for reporting. Will take a look at your sample app ASAP.

pedromschmitt commented 3 years ago

Hi @holidayworking! Are you using Apartment::Activejob - https://github.com/rails-on-services/apartment-activejob?

rpbaltazar commented 3 years ago

Sorry for my absence. It's been very difficult for me to follow up with everything. I've done a bit of backtracing and it seems that when the Active job runs the callbacks it resets the connection. I'm trying to figure out why, right now, but as soon as I've removed the ActiveJob::Callbacks.run_callbacks(:execute) doall is working perfectly fine

rpbaltazar commented 3 years ago

I've looked at the original gem and some people were complaining about it as well. https://github.com/influitive/apartment-sidekiq/issues/27 The solution proposed here: https://github.com/influitive/apartment-sidekiq/issues/27#issuecomment-552514444 with the fix mentioned here: https://github.com/influitive/apartment-sidekiq/issues/27#issuecomment-558800428 seems to actually solve the problem. What i don't like about it is that we're polluting the job arguments so your perform method will need to receive {} as an argument.

I'll try to play a bit with this solution and have a workaround to make it cleaner

cgratigny commented 3 years ago

@rpbaltazar I'm experiencing the problem from https://github.com/influitive/apartment-sidekiq/issues/27#issuecomment-552514444 myself, even though I followed everything that was recommended there, in passing in the args - I'm stuck with running sidekiq with only 1 concurrent job at a time, something that is going to be affecting scaling. As this will affect us as we scale, I'm able to spend time troubleshooting as well - and happy to contribute.

2020-12-27T01:54:54.390Z pid=79439 tid=m07 WARN: ActiveRecord::ConnectionNotEstablished: No connection pool with 'primary' found.
2020-12-27T01:54:54.390Z pid=79439 tid=m07 WARN: /Users/cgratigny/.rvm/gems/ruby-2.7.1/gems/activerecord-6.0.3.3/lib/active_record/connection_adapters/abstract/connection_pool.rb:1115:in `retrieve_connection'
/Users/cgratigny/.rvm/gems/ruby-2.7.1/gems/activerecord-6.0.3.3/lib/active_record/connection_handling.rb:221:in `retrieve_connection'
/Users/cgratigny/.rvm/gems/ruby-2.7.1/gems/activerecord-6.0.3.3/lib/active_record/connection_handling.rb:189:in `connection'
/Users/cgratigny/.rvm/rubies/ruby-2.7.1/lib/ruby/2.7.0/forwardable.rb:235:in `connection'
/Users/cgratigny/.rvm/gems/ruby-2.7.1/gems/ros-apartment-2.8.1/lib/apartment/adapters/abstract_adapter.rb:47:in `current'
/Users/cgratigny/.rvm/rubies/ruby-2.7.1/lib/ruby/2.7.0/forwardable.rb:235:in `current'
/Users/cgratigny/Sites/hummingbird/app/models/tenant.rb:39:in `switch_to!'