influitive / apartment

Database multi-tenancy for Rack (and Rails) applications
2.66k stars 464 forks source link

Streaming using ActionController::Live resets current tenant to the default one #600

Closed Looooong closed 5 years ago

Looooong commented 5 years ago

Description

Whenever data are streamed by writing to response buffer from ActionController::Live, the Apartment::Tenant.current is reset back to the default tenant.

Reproduction

Sample project. The project is setup with 2 tenants:

Reproduction steps:

Expected result

Actual behaviour

System configuration

Sample project. Refer to app/controllers/streams_controller.rb

lcjury commented 5 years ago

Each thread as his own connection and ActionController::Live execute actions on different threads.

What I think is happening here, is that you have 2 threads, the one who handles your connection does the switch (and the other is not), some actions of ActionController:Live are executed on the "other thread" who hasn't switched to your test tenant.

from the docs

The final caveat is that your actions are executed in a separate thread than the main thread. Make sure your actions are thread safe, and this shouldn't be a problem (don't share state across threads, etc).

~You're trying to share state across threads.~ (EDIT: mi assumption is wrong)

Looooong commented 5 years ago

I can understand that the entire action is executed in a child thread. Moreover, the main thread's locals is copied to the child thread. However, I don't get why current tenant is switched in the middle of the action after a call to response.stream.write.

If I modify the action like this, it works as expected:

  def show
    response.headers['Content-Type'] = 'text/event-stream'
    render plain: Array.new(PRINT_TIMES) { Apartment::Tenant.current }.join("\n")
  ensure
    response.stream.close
  end
mikecmpbll commented 5 years ago

certainly sounds like a threading issue. i don't know enough about how ActionController::Live works unfortunately, without spending a lot of time on this.

Looooong commented 5 years ago

I probably agree with you, this might be a threading issue. I think I will avoid ActionController::Live then.