Просмотр исходного кода

Maintenance: Add timeplan support for schedulers to transform cache cleanup job into a nightly task.

Rolf Schmidt 2 лет назад
Родитель
Сommit
e623d6658e

+ 21 - 0
app/models/concerns/has_timeplan.rb

@@ -0,0 +1,21 @@
+# Copyright (C) 2012-2022 Zammad Foundation, https://zammad-foundation.org/
+
+module HasTimeplan
+  extend ActiveSupport::Concern
+
+  included do
+    store :timeplan
+  end
+
+  def in_timeplan?(time = Time.zone.now)
+    timeplan_calculation.contains?(time)
+  end
+
+  private
+
+  def timeplan_calculation
+    timezone = Setting.get('timezone_default').presence || 'UTC'
+
+    TimeplanCalculation.new(timeplan, timezone)
+  end
+end

+ 1 - 11
app/models/job.rb

@@ -5,10 +5,10 @@ class Job < ApplicationModel
   include ChecksConditionValidation
   include ChecksHtmlSanitized
   include ChecksPerformValidation
+  include HasTimeplan
 
   include Job::Assets
 
-  store     :timeplan
   store     :condition
   store     :perform
   validates :name, presence: true
@@ -80,10 +80,6 @@ job.run(true)
     true
   end
 
-  def in_timeplan?(time = Time.zone.now)
-    timeplan_calculation.contains?(time)
-  end
-
   def matching_count
     ticket_count, _tickets = Ticket.selectors(condition, limit: 1, execution_time: true)
     ticket_count || 0
@@ -184,10 +180,4 @@ job.run(true)
         end
     end
   end
-
-  def timeplan_calculation
-    timezone = Setting.get('timezone_default').presence || 'UTC'
-
-    Job::TimeplanCalculation.new(timeplan, timezone)
-  end
 end

+ 16 - 8
app/models/scheduler.rb

@@ -2,6 +2,7 @@
 
 class Scheduler < ApplicationModel
   include ChecksHtmlSanitized
+  include HasTimeplan
 
   extend ::Mixin::StartFinishLogger
 
@@ -43,15 +44,8 @@ class Scheduler < ApplicationModel
       # read/load jobs and check if each has already been started
       jobs = Scheduler.where(active: true).order(prio: :asc)
       jobs.each do |job|
+        _try_job(job)
 
-        # ignore job is still running
-        next if skip_job?(job)
-
-        # check job.last_run
-        next if job.last_run && job.period && job.last_run > (Time.zone.now - job.period)
-
-        # run job as own thread
-        @@jobs_started[ job.id ] = start_job(job)
         sleep 10
       end
       sleep 60
@@ -278,6 +272,20 @@ class Scheduler < ApplicationModel
     end
   end
 
+  def self._try_job(job)
+    # ignore job is still running
+    return if skip_job?(job)
+
+    # check job.last_run
+    return if job.last_run && job.period && job.last_run > (Time.zone.now - job.period)
+
+    # timeplan is optional
+    # but if timeplan is present
+    return if job.timeplan.present? && !job.in_timeplan?(Time.zone.now)
+
+    @@jobs_started[ job.id ] = start_job(job)
+  end
+
   def self._start_job(job, try_count = 0, try_run_time = Time.zone.now)
     started_at = Time.zone.now
     job.update!(

+ 1 - 0
db/migrate/20120101000001_create_base.rb

@@ -530,6 +530,7 @@ class CreateBase < ActiveRecord::Migration[4.2]
       t.string :error_message,                          null: true
       t.string :status,                                 null: true
       t.boolean :active,                                null: false, default: false
+      t.string :timeplan,                 limit: 2500,  null: true
       t.integer :updated_by_id,                         null: false
       t.integer :created_by_id,                         null: false
       t.timestamps limit: 3, null: false

+ 32 - 0
db/migrate/20220405093706_timeplan_nightly.rb

@@ -0,0 +1,32 @@
+# Copyright (C) 2012-2022 Zammad Foundation, https://zammad-foundation.org/
+
+class TimeplanNightly < ActiveRecord::Migration[6.1]
+  def change
+    # return if it's a new setup
+    return if !Setting.exists?(name: 'system_init_done')
+
+    add_column :schedulers, :timeplan, :string, limit: 2500, null: true
+    Scheduler.reset_column_information
+
+    Scheduler.find_by(name: 'Clean up cache.').update(
+      period:   10.minutes,
+      timeplan: {
+        'days'    => {
+          'Mon' => true,
+          'Tue' => true,
+          'Wed' => true,
+          'Thu' => true,
+          'Fri' => true,
+          'Sat' => true,
+          'Sun' => true
+        },
+        'hours'   => {
+          '23' => true
+        },
+        'minutes' => {
+          '0' => true
+        }
+      }
+    )
+  end
+end

+ 18 - 1
db/seeds/schedulers.rb

@@ -223,9 +223,26 @@ Scheduler.create_if_not_exists(
 Scheduler.create_if_not_exists(
   name:          __('Clean up cache.'),
   method:        'CacheClearJob.perform_now',
-  period:        1.day,
+  period:        10.minutes,
   prio:          2,
   active:        true,
+  timeplan:      {
+    'days'    => {
+      'Mon' => true,
+      'Tue' => true,
+      'Wed' => true,
+      'Thu' => true,
+      'Fri' => true,
+      'Sat' => true,
+      'Sun' => true
+    },
+    'hours'   => {
+      '23' => true
+    },
+    'minutes' => {
+      '0' => true
+    }
+  },
   updated_by_id: 1,
   created_by_id: 1,
 )

+ 1 - 1
app/models/job/timeplan_calculation.rb → lib/timeplan_calculation.rb

@@ -1,6 +1,6 @@
 # Copyright (C) 2012-2022 Zammad Foundation, https://zammad-foundation.org/
 
-class Job::TimeplanCalculation
+class TimeplanCalculation
   DAY_MAP = {
     0 => 'Sun',
     1 => 'Mon',

+ 1 - 1
spec/models/job/timeplan_calculation_spec.rb → spec/lib/timeplan_calculation_spec.rb

@@ -2,7 +2,7 @@
 
 require 'rails_helper'
 
-RSpec.describe Job::TimeplanCalculation do
+RSpec.describe TimeplanCalculation do
   subject(:instance) { described_class.new(timeplan, timezone) }
 
   let(:timezone) { nil }

+ 21 - 0
spec/models/concerns/has_timeplan_examples.rb

@@ -0,0 +1,21 @@
+# Copyright (C) 2012-2022 Zammad Foundation, https://zammad-foundation.org/
+
+RSpec.shared_examples 'HasTimeplan' do
+  subject { create(described_class.name.underscore) }
+
+  describe '#in_timeplan?' do
+    before do
+      subject.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(subject).to be_in_timeplan Time.zone.parse('2020-12-27 22:00')
+    end
+
+    it 'checks in UTC' do
+      expect(subject).to be_in_timeplan Time.zone.parse('2020-12-28 00:00')
+    end
+  end
+end

+ 2 - 16
spec/models/job_spec.rb

@@ -3,12 +3,14 @@
 require 'rails_helper'
 require 'models/application_model_examples'
 require 'models/concerns/has_xss_sanitized_note_examples'
+require 'models/concerns/has_timeplan_examples'
 
 RSpec.describe Job, type: :model do
   subject(:job) { create(:job) }
 
   it_behaves_like 'ApplicationModel', can_assets: { selectors: %i[condition perform] }
   it_behaves_like 'HasXssSanitizedNote', model_factory: :job
+  it_behaves_like 'HasTimeplan'
 
   describe 'Class methods:' do
     describe '.run' do
@@ -345,22 +347,6 @@ 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

Некоторые файлы не были показаны из-за большого количества измененных файлов