【问题标题】:Ruby why are class instance variables threadsafeRuby为什么类实例变量是线程安全的
【发布时间】:2014-09-20 21:40:31
【问题描述】:

根据this 的回答,它们是,但后来发帖者指出 JRuby 中的工作方式不同,所以我很困惑?

我正在使用类实例变量实现多租户解决方案,因此无论我使用什么 Ruby 实现或 Web 服务器,我都需要确保数据不会泄露。

这是我的代码:

class Tenant < ActiveRecord::Base

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

  def self.current_tenant
    @tenant
  end
end

我需要做些什么来确保无论发生什么(更改 Ruby 实现、更改 Web 服务器、新的 Ruby 线程功能等)我的代码都是线程安全的?

【问题讨论】:

  • 租期是机器的属性吗?会议?请求?
  • 租户是在url中设置的,所以是请求的一个属性
  • 因此将其设置为 class 变量是没有意义的——它会影响整个系统(或确切地说是进程)——而不仅仅是请求
  • 所以一旦 Rails 加载完毕,所有请求都会设置相同的实例变量(与内存位置相同)

标签: ruby-on-rails ruby


【解决方案1】:

由于tenancy属性的作用域是一个请求,我建议你将它保留在当前线程的作用域内。由于一个请求是在单个线程上处理的,并且一个线程一次处理一个请求 - 只要您始终在请求开始时设置租户就可以了(为了额外的安全性,您可能希望取消 -在请求结束时分配租户)。

为此,您可以使用thread local 属性:

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

由于这是使用线程存储,因此您是完全线程安全的 - 每个线程负责自己的数据。

【讨论】:

  • 如果我想记住一些繁重函数的结果怎么办。我需要使用 Thread.current 还是可以继续在 JRuby 上使用类的实例变量?是否有可能多次调用重函数?
  • @Zhomart - 没有什么能阻止一个繁重的函数在不同的线程上被多次调用,有人可能会争辩说这样做的机会更大,因为函数需要更长的时间完成,所以有更多机会已经在运行......
  • 我最近使用一个类实例变量来记忆一个繁重的函数,一旦我部署到生产环境(使用 nginx),一切都出错了,每个页面刷新数据都用不同的模型数据更改(我可以查明问题的记忆)。然后我将 memoization 移到模型上的实例方法中,一切正常。为什么会这样,因为类实例变量也应该是线程安全的?
  • @sandre89 - 几乎没有足够的信息来帮助你,你应该问一个新问题,用你的代码和所有细节来获得足够的回应。不过,我的猜测是,您的问题与线程安全无关。
猜你喜欢
  • 1970-01-01
  • 2012-05-02
  • 1970-01-01
  • 2012-01-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-05-28
  • 2018-11-07
相关资源
最近更新 更多