9

According to this answer they are, but then the poster states that things work differently in JRuby so I am confused?

I am implementing a multi tenancy solution using class instance variables, so it doesn't matter what Ruby implementation or web server I am using, I need to make sure that data cannot be leaked.

Here is my code:

class Tenant < ActiveRecord::Base

  def self.current_tenant=(tenant)
    @tenant = tenant
  end

  def self.current_tenant
    @tenant
  end
end

What do I need to do to make sure that no matter what happens (changing Ruby implementation, changing web server, new Ruby threading capabilities etc) that my code is thread safe?

Community
  • 1
  • 1
Lee
  • 8,354
  • 14
  • 55
  • 90
  • tenancy is an attribute of the machine? the session? the request? – Uri Agassi Jul 29 '14 at 13:38
  • The tenant is set in the url, so it is an attribute of the request – Lee Jul 29 '14 at 13:39
  • So it does not make sense to set it as a _class_ variable - it would affect the entire system (or process to be exact) - not just the request – Uri Agassi Jul 29 '14 at 13:41
  • So once Rails has loaded, all requests will set the same instance variable (same as in memory location) – Lee Jul 29 '14 at 13:46

1 Answers1

14

Since the tenancy attribute's scope is a request, I would suggest you keep it in the scope of the current thread. Since a request is handled on a single thread, and a thread handles a single request at a time - as long as you always set the tenancy at the beginning of the request you will be fine (for extra security, you might want to un-assign the tenant at the end of the request).

To do this you can use thread local attributes:

class Tenant < ActiveRecord::Base

  def self.current_tenant=(tenant)
    Thread.current[:current_tenant] = tenant
  end

  def self.current_tenant
    Thread.current[:current_tenant]
  end

  def self.clear_current_tenant
    Thread.current[:current_tenant] = nil
  end
end

Since this is using a thread store, you are totally thread safe - each thread is responsible for its own data.

Uri Agassi
  • 36,848
  • 14
  • 76
  • 93
  • 1
    What if I wanted to memoize results of some heavy function. Do I need to use Thread.current or I can continue using instance variable of the class on JRuby? Is there chance that heavy function will be called more than once? – Zhomart Jul 29 '15 at 17:09
  • @Zhomart - nothing prevents a heavy function from being called more than once on different threads, one might argue that there is a _greater_ chance for that, since the function takes longer to finish, so there is more chance that one is already running... – Uri Agassi Jul 30 '15 at 05:49
  • I recently used a class instance variable to memoize a heavy function and as soon as I deployed to production (using nginx) everything went wrong, every page refresh the data changed with a different model data (and I could pinpoint the issue to the memoization). I then moved the memoization to an instance method on the model and everything worked fine. Why is that since class instance variables should be thread safe as well? – sandre89 Oct 08 '17 at 20:47
  • @sandre89 - there is hardly enough information to help you, you should ask a new question, with you code, and all the details to get an adequate response. My guess is, though, that your problems have nothing to do with thread safety. – Uri Agassi Oct 09 '17 at 05:56