ActiveJobLock enhancements (cleanup and Delayed::Job destroy sync)
This commit is contained in:
parent
ff6b4256e1
commit
4c9919a23e
8 changed files with 119 additions and 0 deletions
7
app/jobs/active_job_lock_cleanup_job.rb
Normal file
7
app/jobs/active_job_lock_cleanup_job.rb
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
class ActiveJobLockCleanupJob < ApplicationJob
|
||||||
|
include HasActiveJobLock
|
||||||
|
|
||||||
|
def perform(diff = 1.day)
|
||||||
|
::ActiveJobLock.where('created_at < ?', Time.zone.now - diff).destroy_all
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,20 @@
|
||||||
|
require 'delayed_job'
|
||||||
|
|
||||||
|
module Delayed
|
||||||
|
class Job < ::ActiveRecord::Base
|
||||||
|
|
||||||
|
after_destroy :remove_active_job_lock
|
||||||
|
|
||||||
|
def remove_active_job_lock
|
||||||
|
# only ActiveJob Delayed::Jobs can have a lock
|
||||||
|
return if !payload_object.is_a?(::ActiveJob::QueueAdapters::DelayedJobAdapter::JobWrapper)
|
||||||
|
|
||||||
|
# deserialize ActiveJob and load it's arguments to generate the lock_key
|
||||||
|
active_job = ::ActiveJob::Base.deserialize(payload_object.job_data)
|
||||||
|
active_job.arguments = ::ActiveJob::Arguments.deserialize(active_job.instance_variable_get(:@serialized_arguments))
|
||||||
|
|
||||||
|
# remove possible lock
|
||||||
|
active_job.try(:release_active_job_lock!)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,15 @@
|
||||||
|
class ActiveJobLockCleanupJobScheduler < ActiveRecord::Migration[5.2]
|
||||||
|
def up
|
||||||
|
return if !Setting.find_by(name: 'system_init_done')
|
||||||
|
|
||||||
|
Scheduler.create_or_update(
|
||||||
|
name: 'Cleanup ActiveJob locks.',
|
||||||
|
method: 'ActiveJobLockCleanupJob.perform_now',
|
||||||
|
period: 1.day,
|
||||||
|
prio: 2,
|
||||||
|
active: true,
|
||||||
|
updated_by_id: 1,
|
||||||
|
created_by_id: 1,
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
|
@ -127,6 +127,15 @@ Scheduler.create_or_update(
|
||||||
updated_by_id: 1,
|
updated_by_id: 1,
|
||||||
created_by_id: 1,
|
created_by_id: 1,
|
||||||
)
|
)
|
||||||
|
Scheduler.create_or_update(
|
||||||
|
name: 'Cleanup ActiveJob locks.',
|
||||||
|
method: 'ActiveJobLockCleanupJob.perform_now',
|
||||||
|
period: 1.day,
|
||||||
|
prio: 2,
|
||||||
|
active: true,
|
||||||
|
updated_by_id: 1,
|
||||||
|
created_by_id: 1,
|
||||||
|
)
|
||||||
Scheduler.create_or_update(
|
Scheduler.create_or_update(
|
||||||
name: 'Sync calendars with ical feeds.',
|
name: 'Sync calendars with ical feeds.',
|
||||||
method: 'Calendar.sync',
|
method: 'Calendar.sync',
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
require 'rails_helper'
|
||||||
|
|
||||||
|
RSpec.describe ActiveJobLockCleanupJobScheduler, type: :db_migration do
|
||||||
|
|
||||||
|
let(:scheduler_method) { 'ActiveJobLockCleanupJob.perform_now' }
|
||||||
|
|
||||||
|
context 'New system', system_init_done: false do
|
||||||
|
it 'has no work to do' do
|
||||||
|
expect { migrate }.not_to change { Scheduler.exists?(method: scheduler_method) }.from(true)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'System that is already set up' do
|
||||||
|
|
||||||
|
before do
|
||||||
|
Scheduler.find_by(method: scheduler_method).destroy!
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'creates Scheduler' do
|
||||||
|
expect { migrate }.to change { Scheduler.exists?(method: scheduler_method) }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
27
spec/jobs/active_job_lock_cleanup_job_spec.rb
Normal file
27
spec/jobs/active_job_lock_cleanup_job_spec.rb
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
require 'rails_helper'
|
||||||
|
|
||||||
|
RSpec.describe ActiveJobLockCleanupJob, type: :job do
|
||||||
|
|
||||||
|
context 'when ActiveJobLock records older than a day are present' do
|
||||||
|
|
||||||
|
before do
|
||||||
|
create(:active_job_lock, created_at: 1.day.ago)
|
||||||
|
travel 1.minute
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'cleans up those jobs' do
|
||||||
|
expect { described_class.perform_now }.to change(ActiveJobLock, :count).by(-1)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when recent ActiveJobLock records are present' do
|
||||||
|
|
||||||
|
before do
|
||||||
|
create(:active_job_lock, created_at: 1.minute.ago)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'keeps those jobs' do
|
||||||
|
expect { described_class.perform_now }.not_to change(ActiveJobLock, :count)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -80,6 +80,23 @@ RSpec.describe HasActiveJobLock, type: :job do
|
||||||
it 'allows execution of perform_now jobs' do
|
it 'allows execution of perform_now jobs' do
|
||||||
expect { job_class.perform_now }.to change(job_class, :perform_counter).by(1)
|
expect { job_class.perform_now }.to change(job_class, :perform_counter).by(1)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'when Delayed::Job gets destroyed' do
|
||||||
|
|
||||||
|
before do
|
||||||
|
::ActiveJob::Base.queue_adapter = :delayed_job
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'is ensured that ActiveJobLock gets removed' do
|
||||||
|
job = job_class.perform_later
|
||||||
|
|
||||||
|
expect do
|
||||||
|
Delayed::Job.find(job.provider_job_id).destroy!
|
||||||
|
end.to change {
|
||||||
|
ActiveJobLock.exists?(lock_key: job.lock_key, active_job_id: job.job_id)
|
||||||
|
}.to(false)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'dynamic lock key' do
|
context 'dynamic lock key' do
|
||||||
|
|
|
@ -33,6 +33,7 @@ RSpec.configure do |config|
|
||||||
|
|
||||||
example.run
|
example.run
|
||||||
|
|
||||||
|
ensure
|
||||||
::ActiveJob::Base.queue_adapter = default_queue_adapter
|
::ActiveJob::Base.queue_adapter = default_queue_adapter
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue