Skip to content

Commit

Permalink
Add FoiAttachmentMaskJob uniqueness methods
Browse files Browse the repository at this point in the history
Instead of locking jobs to prevent them from running add checks for
existing jobs before performing/enqueuing attempting to ensure we
execute once only.

These methods only work if Sidekiq is used as the ActiveJob adapter.
  • Loading branch information
gbp committed Oct 10, 2023
1 parent f166d04 commit 6f61c35
Show file tree
Hide file tree
Showing 6 changed files with 92 additions and 3 deletions.
2 changes: 1 addition & 1 deletion app/controllers/attachment_masks_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ def wait
)

else
FoiAttachmentMaskJob.perform_later(@attachment)
FoiAttachmentMaskJob.perform_once_later(@attachment)
end
end

Expand Down
2 changes: 1 addition & 1 deletion app/controllers/attachments_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ def show
if @attachment.masked?
render body: @attachment.body, content_type: content_type
else
FoiAttachmentMaskJob.perform_later(@attachment)
FoiAttachmentMaskJob.perform_once_later(@attachment)

Timeout.timeout(5) do
until @attachment.masked?
Expand Down
2 changes: 2 additions & 0 deletions app/jobs/foi_attachment_mask_job.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
# FoiAttachmentMaskJob.perform(FoiAttachment.first)
#
class FoiAttachmentMaskJob < ApplicationJob
include Uniqueness

queue_as :default

attr_reader :attachment
Expand Down
34 changes: 34 additions & 0 deletions app/jobs/foi_attachment_mask_job/uniqueness.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
##
# Module to add methods to check for existing jobs before performing/enqueuing
# attempting to ensure we execute once only.
#
# These methods only work if Sidekiq is used as the ActiveJob adapter.
#
module FoiAttachmentMaskJob::Uniqueness
def self.included(base)
base.extend ClassMethods
end

module ClassMethods

Check warning on line 12 in app/jobs/foi_attachment_mask_job/uniqueness.rb

View workflow job for this annotation

GitHub Actions / build

[rubocop] reported by reviewdog 🐶 Style/Documentation: Missing top-level documentation comment for module FoiAttachmentMaskJob::Uniqueness::ClassMethods. Raw Output: app/jobs/foi_attachment_mask_job/uniqueness.rb:12:3: C: Style/Documentation: Missing top-level documentation comment for module FoiAttachmentMaskJob::Uniqueness::ClassMethods. module ClassMethods ^^^^^^^^^^^^^^^^^^^
def perform_once_later(attachment)
perform_later(attachment) unless existing_job(attachment)
end

def perform_once_now(attachment)
existing_job(attachment)&.delete
perform_now(attachment)
end

def existing_job(attachment)
return unless queue_adapter.is_a?(
ActiveJob::QueueAdapters::SidekiqAdapter
)

queue = Sidekiq::Queue.new(queue_name)
queue.find do |j|
gid = j.display_args.first['_aj_globalid']
gid == attachment.to_gid.to_s
end
end
end
end
2 changes: 1 addition & 1 deletion app/models/foi_attachment.rb
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ def body
if masked?
@cached_body = file.download
elsif persisted?
FoiAttachmentMaskJob.perform_now(self)
FoiAttachmentMaskJob.perform_once_now(self)
reload
body
end
Expand Down
53 changes: 53 additions & 0 deletions spec/jobs/foi_attachment_mask_job_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -139,4 +139,57 @@ def perform
expect(new_attachment.body).to include 'Banana'
end
end

describe '.perform_once_later' do
it 'call perform_later' do
expect(FoiAttachmentMaskJob).to receive(:perform_later)
FoiAttachmentMaskJob.perform_once_later(attachment)
end

it 'does not call perform_later if existing job is present' do
allow(FoiAttachmentMaskJob).to receive(:existing_job).and_return(double)
expect(FoiAttachmentMaskJob).to_not receive(:perform_later)
FoiAttachmentMaskJob.perform_once_later(attachment)
end
end

describe '.perform_once_now' do
it 'deleted existing job if present' do
job = double(:job)
allow(FoiAttachmentMaskJob).to receive(:existing_job).and_return(job)
expect(job).to receive(:delete)
FoiAttachmentMaskJob.perform_once_now(attachment)
end

it 'calls perform_now' do
expect(FoiAttachmentMaskJob).to receive(:perform_now)
FoiAttachmentMaskJob.perform_once_now(attachment)
end
end

describe '.existing_job' do
around do |example|
adapter = ActiveJob::Base.queue_adapter
ActiveJob::Base.queue_adapter = :sidekiq
example.call
ActiveJob::Base.queue_adapter = adapter
end

before do
allow(FoiAttachmentMaskJob).to receive(:queue_name).and_return('test')
end

after do
Sidekiq::Queue.new('test').clear
end

it 'return nil if existing job is not present' do
expect(FoiAttachmentMaskJob.existing_job(attachment)).to be_nil
end

it 'return existing job if present' do
FoiAttachmentMaskJob.perform_later(attachment)
expect(FoiAttachmentMaskJob.existing_job(attachment)).to_not be_nil
end
end
end

0 comments on commit 6f61c35

Please sign in to comment.