aboutsummaryrefslogtreecommitdiffstats
path: root/activejob
diff options
context:
space:
mode:
authorAndrew White <andrew.white@unboxed.co>2018-02-22 14:14:42 +0000
committerAndrew White <andrew.white@unboxed.co>2018-02-22 14:14:42 +0000
commita9d1167b1fdae6f5f5496738b3e7d1e05949dcd0 (patch)
tree8a46f129aaed18c7c48b35aa0e48f9a19c1bc219 /activejob
parent9c0c90979a759a41628e0cd9d73821b0b34d03fc (diff)
downloadrails-a9d1167b1fdae6f5f5496738b3e7d1e05949dcd0.tar.gz
rails-a9d1167b1fdae6f5f5496738b3e7d1e05949dcd0.tar.bz2
rails-a9d1167b1fdae6f5f5496738b3e7d1e05949dcd0.zip
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.
Diffstat (limited to 'activejob')
-rw-r--r--activejob/CHANGELOG.md8
-rw-r--r--activejob/lib/active_job/base.rb2
-rw-r--r--activejob/lib/active_job/core.rb7
-rw-r--r--activejob/lib/active_job/timezones.rb13
-rw-r--r--activejob/test/cases/job_serialization_test.rb7
-rw-r--r--activejob/test/cases/timezones_test.rb24
-rw-r--r--activejob/test/integration/queuing_test.rb16
-rw-r--r--activejob/test/jobs/timezone_dependent_job.rb22
-rw-r--r--activejob/test/support/integration/dummy_app_template.rb1
-rw-r--r--activejob/test/support/integration/test_case_helpers.rb4
10 files changed, 103 insertions, 1 deletions
diff --git a/activejob/CHANGELOG.md b/activejob/CHANGELOG.md
index 097433c3d0..c6a3ad8ade 100644
--- a/activejob/CHANGELOG.md
+++ b/activejob/CHANGELOG.md
@@ -1,5 +1,13 @@
## 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.
*Jeremy Daer*
diff --git a/activejob/lib/active_job/base.rb b/activejob/lib/active_job/base.rb
index 6194f89956..2b2a59e969 100644
--- a/activejob/lib/active_job/base.rb
+++ b/activejob/lib/active_job/base.rb
@@ -9,6 +9,7 @@ require "active_job/execution"
require "active_job/callbacks"
require "active_job/exceptions"
require "active_job/logging"
+require "active_job/timezones"
require "active_job/translation"
module ActiveJob #:nodoc:
@@ -68,6 +69,7 @@ module ActiveJob #:nodoc:
include Callbacks
include Exceptions
include Logging
+ include Timezones
include Translation
ActiveSupport.run_load_hooks(:active_job, self)
diff --git a/activejob/lib/active_job/core.rb b/activejob/lib/active_job/core.rb
index 879746fc01..da841ae45b 100644
--- a/activejob/lib/active_job/core.rb
+++ b/activejob/lib/active_job/core.rb
@@ -31,6 +31,9 @@ module ActiveJob
# I18n.locale to be used during the job.
attr_accessor :locale
+
+ # Timezone to be used during the job.
+ attr_accessor :timezone
end
# These methods will be included into any Active Job object, adding
@@ -87,7 +90,8 @@ module ActiveJob
"priority" => priority,
"arguments" => serialize_arguments(arguments),
"executions" => executions,
- "locale" => I18n.locale.to_s
+ "locale" => I18n.locale.to_s,
+ "timezone" => Time.zone.try(:name)
}
end
@@ -125,6 +129,7 @@ module ActiveJob
self.serialized_arguments = job_data["arguments"]
self.executions = job_data["executions"]
self.locale = job_data["locale"] || I18n.locale.to_s
+ self.timezone = job_data["timezone"] || Time.zone.try(:name)
end
private
diff --git a/activejob/lib/active_job/timezones.rb b/activejob/lib/active_job/timezones.rb
new file mode 100644
index 0000000000..83f459aea5
--- /dev/null
+++ b/activejob/lib/active_job/timezones.rb
@@ -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
diff --git a/activejob/test/cases/job_serialization_test.rb b/activejob/test/cases/job_serialization_test.rb
index 440051c427..5c9994508e 100644
--- a/activejob/test/cases/job_serialization_test.rb
+++ b/activejob/test/cases/job_serialization_test.rb
@@ -54,4 +54,11 @@ class JobSerializationTest < ActiveSupport::TestCase
job.provider_job_id = "some value set by adapter"
assert_equal job.provider_job_id, job.serialize["provider_job_id"]
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
diff --git a/activejob/test/cases/timezones_test.rb b/activejob/test/cases/timezones_test.rb
new file mode 100644
index 0000000000..e2095b020d
--- /dev/null
+++ b/activejob/test/cases/timezones_test.rb
@@ -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
diff --git a/activejob/test/integration/queuing_test.rb b/activejob/test/integration/queuing_test.rb
index 32ef485c45..7a95d3d039 100644
--- a/activejob/test/integration/queuing_test.rb
+++ b/activejob/test/integration/queuing_test.rb
@@ -110,6 +110,22 @@ class QueuingTest < ActiveSupport::TestCase
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
skip unless adapter_is?(:delayed_job, :que)
diff --git a/activejob/test/jobs/timezone_dependent_job.rb b/activejob/test/jobs/timezone_dependent_job.rb
new file mode 100644
index 0000000000..41f473d533
--- /dev/null
+++ b/activejob/test/jobs/timezone_dependent_job.rb
@@ -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
diff --git a/activejob/test/support/integration/dummy_app_template.rb b/activejob/test/support/integration/dummy_app_template.rb
index 7ea78c3350..b56dd3e591 100644
--- a/activejob/test/support/integration/dummy_app_template.rb
+++ b/activejob/test/support/integration/dummy_app_template.rb
@@ -21,6 +21,7 @@ class TestJob < ActiveJob::Base
File.open(Rails.root.join("tmp/\#{x}.new"), "wb+") do |f|
f.write Marshal.dump({
"locale" => I18n.locale.to_s || "en",
+ "timezone" => Time.zone.try(:name) || "UTC",
"executed_at" => Time.now.to_r
})
end
diff --git a/activejob/test/support/integration/test_case_helpers.rb b/activejob/test/support/integration/test_case_helpers.rb
index f02a32a38e..3d9b265b66 100644
--- a/activejob/test/support/integration/test_case_helpers.rb
+++ b/activejob/test/support/integration/test_case_helpers.rb
@@ -62,4 +62,8 @@ module TestCaseHelpers
def job_executed_in_locale(id = @id)
job_data(id)["locale"]
end
+
+ def job_executed_in_timezone(id = @id)
+ job_data(id)["timezone"]
+ end
end