Fixes #3802 - Job scheduling respects time zone
This commit is contained in:
parent
3f48c222b5
commit
e26d3ecfd3
4 changed files with 87 additions and 9 deletions
|
@ -81,7 +81,7 @@ job.run(true)
|
|||
end
|
||||
|
||||
def in_timeplan?(time = Time.zone.now)
|
||||
Job::TimeplanCalculation.new(timeplan).contains?(time)
|
||||
timeplan_calculation.contains?(time)
|
||||
end
|
||||
|
||||
def matching_count
|
||||
|
@ -89,6 +89,8 @@ job.run(true)
|
|||
ticket_count || 0
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def next_run_at_calculate(time = Time.zone.now)
|
||||
return nil if !active
|
||||
|
||||
|
@ -96,11 +98,9 @@ job.run(true)
|
|||
time += 10.minutes
|
||||
end
|
||||
|
||||
Job::TimeplanCalculation.new(timeplan).next_at(time)
|
||||
timeplan_calculation.next_at(time)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def updated_matching
|
||||
self.matching = matching_count
|
||||
end
|
||||
|
@ -184,4 +184,10 @@ job.run(true)
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
def timeplan_calculation
|
||||
timezone = Setting.get('timezone_default').presence || 'UTC'
|
||||
|
||||
Job::TimeplanCalculation.new(timeplan, timezone)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -13,24 +13,33 @@ class Job::TimeplanCalculation
|
|||
|
||||
attr_reader :timeplan
|
||||
|
||||
def initialize(timeplan)
|
||||
def initialize(timeplan, timezone)
|
||||
@timeplan = timeplan.deep_transform_keys(&:to_s)
|
||||
@timezone = timezone
|
||||
end
|
||||
|
||||
def contains?(time)
|
||||
return false if !valid?
|
||||
|
||||
day?(time) && hour?(time) && minute?(time)
|
||||
time_in_zone = ensure_matching_time(time)
|
||||
|
||||
day?(time_in_zone) && hour?(time_in_zone) && minute?(time_in_zone)
|
||||
end
|
||||
|
||||
def next_at(time)
|
||||
return nil if !valid?
|
||||
|
||||
next_run_at_same_day(time) || next_run_at_coming_week(time)
|
||||
time_in_zone = ensure_matching_time(time)
|
||||
|
||||
next_run_at_same_day(time_in_zone) || next_run_at_coming_week(time_in_zone)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def ensure_matching_time(time)
|
||||
time.in_time_zone @timezone
|
||||
end
|
||||
|
||||
def valid?
|
||||
timeplan.key?('days') && timeplan.key?('hours') && timeplan.key?('minutes')
|
||||
end
|
||||
|
|
|
@ -3,7 +3,9 @@
|
|||
require 'rails_helper'
|
||||
|
||||
RSpec.describe Job::TimeplanCalculation do
|
||||
subject(:instance) { described_class.new(timeplan) }
|
||||
subject(:instance) { described_class.new(timeplan, timezone) }
|
||||
|
||||
let(:timezone) { nil }
|
||||
|
||||
describe '#contains?' do
|
||||
context 'without a valid timeplan' do
|
||||
|
@ -55,9 +57,17 @@ RSpec.describe Job::TimeplanCalculation do
|
|||
it { is_expected.not_to be_contains(Time.zone.parse('2020-12-22 9:20')) }
|
||||
it { is_expected.not_to be_contains(Time.zone.parse('2020-12-20 9:20')) }
|
||||
end
|
||||
|
||||
context 'with monday 09:00 and time zone' do
|
||||
let(:timeplan) { { 'days' => { 'Mon' => true }, 'hours' => { '1' => true }, 'minutes' => { '0' => true } } }
|
||||
let(:timezone) { 'Europe/Vilnius' }
|
||||
|
||||
it { is_expected.to be_contains(Time.use_zone('Europe/Vilnius') { Time.zone.parse('2020-12-21 01:00') }) }
|
||||
it { is_expected.to be_contains(Time.zone.parse('2020-12-20 23:00')) }
|
||||
end
|
||||
end
|
||||
|
||||
describe 'next_at?' do
|
||||
describe '#next_at' do
|
||||
context 'without a valid timeplan' do
|
||||
let(:timeplan) { {} }
|
||||
|
||||
|
@ -125,6 +135,25 @@ RSpec.describe Job::TimeplanCalculation do
|
|||
it { expect(instance.next_at(Time.zone.parse('2020-12-22 9:20'))).to eq(Time.zone.parse('2020-12-28 09:10')) }
|
||||
it { expect(instance.next_at(Time.zone.parse('2020-12-20 9:20'))).to eq(Time.zone.parse('2020-12-21 09:10')) }
|
||||
end
|
||||
|
||||
context 'with monday 09:00 and time zone' do
|
||||
let(:timezone) { 'Europe/Vilnius' }
|
||||
let(:timeplan) { { 'days' => { 'Mon' => true }, 'hours' => { '1' => true }, 'minutes' => { '0' => true } } }
|
||||
|
||||
it 'calculates time respecting time zone' do
|
||||
from = Time.use_zone('Europe/Vilnius') { Time.zone.parse('2020-12-21 01:15') }
|
||||
to = Time.use_zone('Europe/Vilnius') { Time.zone.parse('2020-12-28 01:00') }
|
||||
|
||||
expect(instance.next_at(from)).to eq(to)
|
||||
end
|
||||
|
||||
it 'calculates time converting to time zone' do
|
||||
from = Time.zone.parse('2020-12-20 23:10')
|
||||
to = Time.use_zone('Europe/Vilnius') { Time.zone.parse('2020-12-28 01:00') }
|
||||
|
||||
expect(instance.next_at(from)).to eq(to)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'legacy tests moved from Job model' do
|
||||
|
|
|
@ -345,6 +345,22 @@ RSpec.describe Job, type: :model do
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#in_timeplan?' do
|
||||
before do
|
||||
job.timeplan = { days: { Mon: true }, hours: { 0 => true }, minutes: { 0 => true } }
|
||||
end
|
||||
|
||||
it 'checks in selected time zone' do
|
||||
Setting.set 'timezone_default', 'Europe/Vilnius'
|
||||
|
||||
expect(job).to be_in_timeplan Time.zone.parse('2020-12-27 22:00')
|
||||
end
|
||||
|
||||
it 'checks in UTC' do
|
||||
expect(job).to be_in_timeplan Time.zone.parse('2020-12-28 00:00')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'Attributes:' do
|
||||
|
@ -451,6 +467,24 @@ RSpec.describe Job, type: :model do
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when updating #next_run_at' do
|
||||
before do
|
||||
travel_to Time.zone.parse('2020-12-27 00:00')
|
||||
|
||||
job.timeplan = { days: { Mon: true }, hours: { 0 => true }, minutes: { 0 => true } }
|
||||
end
|
||||
|
||||
it 'sets #next_run_at time in selected time zone' do
|
||||
Setting.set 'timezone_default', 'Europe/Vilnius'
|
||||
|
||||
expect { job.save }.to change(job, :next_run_at).to(Time.zone.parse('2020-12-27 22:00'))
|
||||
end
|
||||
|
||||
it 'sets #next_run_at time in UTC' do
|
||||
expect { job.save }.to change(job, :next_run_at).to(Time.zone.parse('2020-12-28 00:00'))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#perform' do
|
||||
|
|
Loading…
Reference in a new issue