简体   繁体   中英

TimeCop in production on a per-request basis

I've got a rails app using MRI ruby and Unicorn as the app server. The app provides a 10-week fitness program, and I've built a feature for people logged in as admins to be able to "time travel" to different weeks in the program. Basically, it just sets a session variable with the date they're "time travelled" to, and, each request, it time-travels to that point at the beginning, then returns at the end. The code is below.

I'd limited the feature non-production environments, out of fear that one person's time-travelling may affect other users (since TimeCop monkey patches core classes). But, given MRI isn't really multi-threaded I'm now thinking that's an irrational fear, and that there should be no danger of using the "time travel" feature in production.

For the duration within which a single request is processed (and therefore the time for which the core classes are monkey patched by TimeCop if the user is using "time travel"), there should be no possibility that any other request gets run on the same ruby process.

Is this correct? Or can other user's requests be affected by TimeCop's changes to the core classes in a way I'm not aware of?

The code I'm using is as follows:

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

MRI's global interpreter lock does mean that 2 threads won't execute concurrently, but the granularity of that is much much smaller than the processing of one request.

As it happens unicorn doesn't use threads for concurrency so you'd be ok, but the day you switched to another server (eg puma) then you'd be in for a nasty surprise.

This would also affect things like data in logs, created_at/updated_at timestamps for anything updated and so on. It might also affect monitoring data gathered by services like newrelic, airbrake etc if you use those. Another example of something that might seem completely unrelated is api requests to AWS: the signature that verifies these requests includes a timestamp, and they will fail if you're out of sync by more than a few minutes. There is just too much code (much of which you don't control) that assumes that Time.now is accurate.

You'd be much better off identifying those bits of code that implicitly use the current Time and changing them to allow the desired time to be passed as an argument.

As an aside I think your code would leave the altered time in place if the controller raised an exception

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM