我有一个使用MRI ruby和Unicorn作为应用服务器的rails应用程序。该应用程序提供了一个为期10周的健身计划,我为以管理员身份登录的人员构建了一项功能,以便能够在计划中的“时间旅行”到不同的周。基本上,它只是设置一个会话变量,其中包含他们“时间旅行”的日期,并且,每个请求,它在开始时间到达该点,然后在结束时返回。代码如下。
我限制了非生产环境的功能,因为担心一个人的时间旅行可能会影响其他用户(因为TimeCop猴子补丁核心类)。但是,鉴于MRI不是真正的多线程,我现在认为这是一种非理性的恐惧,并且在生产中不应该使用“时间旅行”功能。
对于处理单个请求的持续时间(因此,如果用户使用“时间旅行”,则TimeCop对核心类进行猴子修补的时间),任何其他请求都不可能运行在同一个红宝石过程中。
这是对的吗?或者其他用户的请求会受到我不知道的TimeCop对核心类的更改的影响吗?
我正在使用的代码如下:
module TimeTravelFilters
extend ActiveSupport::Concern
included do
if Rails.env.development? || Rails.env.staging?
around_action :time_travel_for_request
end
end
def time_travel_for_request
time_travel
yield
time_travel_return
end
def time_travel
if session[:timetravel_to_date]
Timecop.travel(session[:timetravel_to_date])
end
end
def time_travel_return
Timecop.return
end
end
答案 0 :(得分:2)
MRI的全局解释器锁确实意味着2个线程不会同时执行,但其粒度远小于一个请求的处理。
正如发生的那样,独角兽并没有使用线程来实现并发性,所以你可以,但是当你切换到另一台服务器的那一天(例如美洲狮)那么你就会陷入令人讨厌的惊喜之中。
这也会影响日志中的数据,已更新的任何内容的created_at / updated_at时间戳等等。它还可能影响由newrelic,airbrake等服务收集的监控数据(如果您使用它们)。可能看起来完全不相关的另一个示例是对AWS的api请求:验证这些请求的签名包括时间戳,如果您超过几分钟不同步,它们将失败。假设Time.now准确无误,代码太多了(其中很多都是你无法控制的)。
在识别那些隐含使用当前时间并更改它们以允许将所需时间作为参数传递的代码时,您会好得多。
另外,我认为如果控制器引发异常
,您的代码将保留更改的时间