Add support for timezones to Active Job
Record what was the current timezone in effect when the job was enqueued and then restore when the job is executed in same way that the current locale is recorded and restored.
This commit is contained in:
parent
9c0c90979a
commit
a9d1167b1f
|
@ -1,5 +1,13 @@
|
||||||
## Rails 6.0.0.alpha (Unreleased) ##
|
## Rails 6.0.0.alpha (Unreleased) ##
|
||||||
|
|
||||||
|
* Add support for timezones to Active Job
|
||||||
|
|
||||||
|
Record what was the current timezone in effect when the job was
|
||||||
|
enqueued and then restore when the job is executed in same way
|
||||||
|
that the current locale is recorded and restored.
|
||||||
|
|
||||||
|
*Andrew White*
|
||||||
|
|
||||||
* Rails 6 requires Ruby 2.4.1 or newer.
|
* Rails 6 requires Ruby 2.4.1 or newer.
|
||||||
|
|
||||||
*Jeremy Daer*
|
*Jeremy Daer*
|
||||||
|
|
|
@ -9,6 +9,7 @@ require "active_job/execution"
|
||||||
require "active_job/callbacks"
|
require "active_job/callbacks"
|
||||||
require "active_job/exceptions"
|
require "active_job/exceptions"
|
||||||
require "active_job/logging"
|
require "active_job/logging"
|
||||||
|
require "active_job/timezones"
|
||||||
require "active_job/translation"
|
require "active_job/translation"
|
||||||
|
|
||||||
module ActiveJob #:nodoc:
|
module ActiveJob #:nodoc:
|
||||||
|
@ -68,6 +69,7 @@ module ActiveJob #:nodoc:
|
||||||
include Callbacks
|
include Callbacks
|
||||||
include Exceptions
|
include Exceptions
|
||||||
include Logging
|
include Logging
|
||||||
|
include Timezones
|
||||||
include Translation
|
include Translation
|
||||||
|
|
||||||
ActiveSupport.run_load_hooks(:active_job, self)
|
ActiveSupport.run_load_hooks(:active_job, self)
|
||||||
|
|
|
@ -31,6 +31,9 @@ module ActiveJob
|
||||||
|
|
||||||
# I18n.locale to be used during the job.
|
# I18n.locale to be used during the job.
|
||||||
attr_accessor :locale
|
attr_accessor :locale
|
||||||
|
|
||||||
|
# Timezone to be used during the job.
|
||||||
|
attr_accessor :timezone
|
||||||
end
|
end
|
||||||
|
|
||||||
# These methods will be included into any Active Job object, adding
|
# These methods will be included into any Active Job object, adding
|
||||||
|
@ -87,7 +90,8 @@ module ActiveJob
|
||||||
"priority" => priority,
|
"priority" => priority,
|
||||||
"arguments" => serialize_arguments(arguments),
|
"arguments" => serialize_arguments(arguments),
|
||||||
"executions" => executions,
|
"executions" => executions,
|
||||||
"locale" => I18n.locale.to_s
|
"locale" => I18n.locale.to_s,
|
||||||
|
"timezone" => Time.zone.try(:name)
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -125,6 +129,7 @@ module ActiveJob
|
||||||
self.serialized_arguments = job_data["arguments"]
|
self.serialized_arguments = job_data["arguments"]
|
||||||
self.executions = job_data["executions"]
|
self.executions = job_data["executions"]
|
||||||
self.locale = job_data["locale"] || I18n.locale.to_s
|
self.locale = job_data["locale"] || I18n.locale.to_s
|
||||||
|
self.timezone = job_data["timezone"] || Time.zone.try(:name)
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module ActiveJob
|
||||||
|
module Timezones #:nodoc:
|
||||||
|
extend ActiveSupport::Concern
|
||||||
|
|
||||||
|
included do
|
||||||
|
around_perform do |job, block, _|
|
||||||
|
Time.use_zone(job.timezone, &block)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -54,4 +54,11 @@ class JobSerializationTest < ActiveSupport::TestCase
|
||||||
job.provider_job_id = "some value set by adapter"
|
job.provider_job_id = "some value set by adapter"
|
||||||
assert_equal job.provider_job_id, job.serialize["provider_job_id"]
|
assert_equal job.provider_job_id, job.serialize["provider_job_id"]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "serialize stores the current timezone" do
|
||||||
|
Time.use_zone "Hawaii" do
|
||||||
|
job = HelloJob.new
|
||||||
|
assert_equal "Hawaii", job.serialize["timezone"]
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require "helper"
|
||||||
|
require "jobs/timezone_dependent_job"
|
||||||
|
|
||||||
|
class TimezonesTest < ActiveSupport::TestCase
|
||||||
|
setup do
|
||||||
|
JobBuffer.clear
|
||||||
|
end
|
||||||
|
|
||||||
|
test "it performs the job in the given timezone" do
|
||||||
|
job = TimezoneDependentJob.new("2018-01-01T00:00:00Z")
|
||||||
|
job.timezone = "London"
|
||||||
|
job.perform_now
|
||||||
|
|
||||||
|
assert_equal "Happy New Year!", JobBuffer.last_value
|
||||||
|
|
||||||
|
job = TimezoneDependentJob.new("2018-01-01T00:00:00Z")
|
||||||
|
job.timezone = "Eastern Time (US & Canada)"
|
||||||
|
job.perform_now
|
||||||
|
|
||||||
|
assert_equal "Just 5 hours to go", JobBuffer.last_value
|
||||||
|
end
|
||||||
|
end
|
|
@ -110,6 +110,22 @@ class QueuingTest < ActiveSupport::TestCase
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "current timezone is kept while running perform_later" do
|
||||||
|
skip if adapter_is?(:inline)
|
||||||
|
|
||||||
|
begin
|
||||||
|
current_zone = Time.zone
|
||||||
|
Time.zone = "Hawaii"
|
||||||
|
|
||||||
|
TestJob.perform_later @id
|
||||||
|
wait_for_jobs_to_finish_for(5.seconds)
|
||||||
|
assert job_executed
|
||||||
|
assert_equal "Hawaii", job_executed_in_timezone
|
||||||
|
ensure
|
||||||
|
Time.zone = current_zone
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
test "should run job with higher priority first" do
|
test "should run job with higher priority first" do
|
||||||
skip unless adapter_is?(:delayed_job, :que)
|
skip unless adapter_is?(:delayed_job, :que)
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require_relative "../support/job_buffer"
|
||||||
|
|
||||||
|
class TimezoneDependentJob < ActiveJob::Base
|
||||||
|
def perform(now)
|
||||||
|
now = now.in_time_zone
|
||||||
|
new_year = localtime(2018, 1, 1)
|
||||||
|
|
||||||
|
if now >= new_year
|
||||||
|
JobBuffer.add("Happy New Year!")
|
||||||
|
else
|
||||||
|
JobBuffer.add("Just #{(new_year - now).div(3600)} hours to go")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def localtime(*args)
|
||||||
|
Time.zone ? Time.zone.local(*args) : Time.utc(*args)
|
||||||
|
end
|
||||||
|
end
|
|
@ -21,6 +21,7 @@ class TestJob < ActiveJob::Base
|
||||||
File.open(Rails.root.join("tmp/\#{x}.new"), "wb+") do |f|
|
File.open(Rails.root.join("tmp/\#{x}.new"), "wb+") do |f|
|
||||||
f.write Marshal.dump({
|
f.write Marshal.dump({
|
||||||
"locale" => I18n.locale.to_s || "en",
|
"locale" => I18n.locale.to_s || "en",
|
||||||
|
"timezone" => Time.zone.try(:name) || "UTC",
|
||||||
"executed_at" => Time.now.to_r
|
"executed_at" => Time.now.to_r
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
|
|
|
@ -62,4 +62,8 @@ module TestCaseHelpers
|
||||||
def job_executed_in_locale(id = @id)
|
def job_executed_in_locale(id = @id)
|
||||||
job_data(id)["locale"]
|
job_data(id)["locale"]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def job_executed_in_timezone(id = @id)
|
||||||
|
job_data(id)["timezone"]
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in New Issue