Skip to content

Commit

Permalink
Allow a checker to be retried in case it fails
Browse files Browse the repository at this point in the history
leochab committed Jun 26, 2024

Verified

This commit was signed with the committer’s verified signature.
timlegge Timothy Legge
1 parent 658f2ac commit 64814ec
Showing 12 changed files with 143 additions and 20 deletions.
3 changes: 2 additions & 1 deletion .rubocop.yml
Original file line number Diff line number Diff line change
@@ -10,7 +10,8 @@ AllCops:
#

Layout/DotPosition:
EnforcedStyle: trailing
Enabled: false
StyleGuide: https://relaxed.ruby.style/#layoutdotposition

Layout/FirstHashElementIndentation:
EnforcedStyle: consistent
18 changes: 15 additions & 3 deletions lib/checker_jobs/checks/base.rb
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
CheckerJobs::Checks::Base = Struct.new(:klass, :name, :options, :block) do
def perform
def perform(iteration = 0)
result = CheckerJobs.configuration.around_check.call do
klass.new.instance_exec(&block)
end

result.tap { |res| handle_result(res) }
result.tap { |res| handle_result(res, iteration) }
end

private
@@ -14,7 +14,19 @@ def notify(count:, entries: nil)
notifier_class.new(self, count, entries).notify
end

def handle_result(_result)
def handle_result(_result, _retry_count)
raise NotImplementedError
end

def handle_retry(count, iteration, entries = nil)
retry?(iteration) ? perform(iteration + 1) : notify(count: count, entries: entries)
end

def retry?(iteration)
iteration < max_retry
end

def max_retry
@_max_retry ||= options.fetch(:retry, 0).clamp(0, 3)
end
end
4 changes: 2 additions & 2 deletions lib/checker_jobs/checks/ensure_fewer.rb
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
class CheckerJobs::Checks::EnsureFewer < CheckerJobs::Checks::Base
private

def handle_result(result)
def handle_result(result, iteration)
case result
when Numeric
notify(count: result) if result > options.fetch(:than)
handle_retry(result, iteration) if result > options.fetch(:than)
else
raise ArgumentError, "Unsupported result: '#{result.class.name}' for 'ensure_less'"
end
4 changes: 2 additions & 2 deletions lib/checker_jobs/checks/ensure_more.rb
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
class CheckerJobs::Checks::EnsureMore < CheckerJobs::Checks::Base
private

def handle_result(result)
def handle_result(result, iteration)
case result
when Numeric
notify(count: result) if result < options.fetch(:than)
handle_retry(result, iteration) if result < options.fetch(:than)
else
raise ArgumentError, "Unsupported result: '#{result.class.name}' for 'ensure_more'"
end
8 changes: 4 additions & 4 deletions lib/checker_jobs/checks/ensure_no.rb
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
class CheckerJobs::Checks::EnsureNo < CheckerJobs::Checks::Base
private

def handle_result(result)
def handle_result(result, iteration)
case result
when Numeric
notify(count: result) unless result.zero?
handle_retry(result, iteration) unless result.zero?
when Enumerable
notify(count: result.size, entries: result) unless result.empty?
handle_retry(result.size, iteration, result) unless result.empty?
when TrueClass, FalseClass
notify(count: 1) if result
handle_retry(1, iteration) if result
else
raise ArgumentError, "Unsupported result: '#{result.class.name}' for 'ensure_no'"
end
6 changes: 3 additions & 3 deletions lib/checker_jobs/notifiers/email.rb
Original file line number Diff line number Diff line change
@@ -28,9 +28,9 @@ def valid?
end

def mailer_options
@_mailer_options ||= @defaults.
merge(email_options).
merge(@check.klass.notifier_options)
@_mailer_options ||= @defaults
.merge(email_options)
.merge(@check.klass.notifier_options)
end

def email_options
2 changes: 1 addition & 1 deletion spec/checker_jobs/checks/base_spec.rb
Original file line number Diff line number Diff line change
@@ -39,7 +39,7 @@
it "keeps handling the result outside the around_check delegation" do
allow(instance).to receive(:handle_result).and_call_original
perform
expect(instance).to have_received(:handle_result).with(0)
expect(instance).to have_received(:handle_result).with(0, 0)
end
end
end
26 changes: 25 additions & 1 deletion spec/checker_jobs/checks/ensure_fewer_spec.rb
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
RSpec.describe CheckerJobs::Checks::EnsureFewer, :bugsnag, :configuration do
include BugsnagHelpers

let(:instance) { described_class.new(checker_klass, "ensure_name", { than: 3 }, block) }
let(:instance) { described_class.new(checker_klass, "ensure_name", options, block) }
let(:checker_klass) do
Class.new do
include CheckerJobs::Base
notify :bugsnag
end
end

let(:options) { { than: 3 } }

describe "#perform" do
subject(:perform) { instance.perform }

@@ -29,5 +31,27 @@

include_examples "sends_a_bugsnag_notification"
end

context "when retry option is used" do
let(:options) { { than: 3, retry: 1 } }

context "when block's result is lower than the threshold" do
let(:block) { Proc.new { 2 } }

include_examples "does_not_send_a_bugsnag_notification"
end

context "when block's result is greater than the threshold" do
let(:block) { Proc.new { 4 } }

it "sends 2 sidekiq jobs" do
allow(instance).to receive(:perform).and_call_original
perform
expect(instance).to have_received(:perform).twice
end

include_examples "sends_a_bugsnag_notification"
end
end
end
end
26 changes: 25 additions & 1 deletion spec/checker_jobs/checks/ensure_more_spec.rb
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
RSpec.describe CheckerJobs::Checks::EnsureMore, :bugsnag, :configuration do
include BugsnagHelpers

let(:instance) { described_class.new(checker_klass, "ensure_name", { than: 3 }, block) }
let(:instance) { described_class.new(checker_klass, "ensure_name", options, block) }
let(:checker_klass) do
Class.new do
include CheckerJobs::Base
notify :bugsnag
end
end

let(:options) { { than: 3 } }

describe "#perform" do
subject(:perform) { instance.perform }

@@ -29,5 +31,27 @@

include_examples "does_not_send_a_bugsnag_notification"
end

context "when retry option is used" do
let(:options) { { than: 3, retry: 1 } }

context "when block's result is greater than the threshold" do
let(:block) { Proc.new { 4 } }

include_examples "does_not_send_a_bugsnag_notification"
end

context "when block's result is lower than the threshold" do
let(:block) { Proc.new { 2 } }

it "sends 2 sidekiq jobs" do
allow(instance).to receive(:perform).and_call_original
perform
expect(instance).to have_received(:perform).twice
end

include_examples "sends_a_bugsnag_notification"
end
end
end
end
47 changes: 46 additions & 1 deletion spec/checker_jobs/checks/ensure_no_spec.rb
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
require "support/checkers"

RSpec.describe CheckerJobs::Checks::EnsureNo, :bugsnag, :configuration do
include BugsnagHelpers

let(:instance) { described_class.new(checker_klass, "ensure_name", {}, block) }
let(:instance) { described_class.new(checker_klass, "ensure_name", options, block) }
let(:checker_klass) do
Class.new do
include CheckerJobs::Base
notify :bugsnag
end
end
let(:options) { {} }

describe "#perform" do
subject(:perform) { instance.perform }
@@ -47,5 +50,47 @@

include_examples "does_not_send_a_bugsnag_notification"
end

context "when retry option is used" do
context "when set to 1 time" do
let(:options) { { retry: 1 } }

context "when block's result is 0" do
let(:block) { Proc.new { 0 } }

include_examples "does_not_send_a_bugsnag_notification"
end

context "when block's result is > 0" do
include_context "when SidekiqChecker is available"
let(:block) { Proc.new { 2 } }

it "sends 2 sidekiq jobs" do
allow(instance).to receive(:perform).and_call_original
perform
expect(instance).to have_received(:perform).twice
end

include_examples "sends_a_bugsnag_notification"
end
end

context "when set to more than the maximum allowed" do
let(:options) { { retry: 8 } }

context "when block's result is > 0" do
include_context "when SidekiqChecker is available"
let(:block) { Proc.new { 2 } }

it "sends 1 more sidekiq jobs than the maximum number of retries" do
allow(instance).to receive(:perform).and_call_original
perform
expect(instance).to have_received(:perform).exactly(4).times
end

include_examples "sends_a_bugsnag_notification"
end
end
end
end
end
2 changes: 1 addition & 1 deletion spec/checker_jobs/notifiers/bugsnag_spec.rb
Original file line number Diff line number Diff line change
@@ -23,7 +23,7 @@
expect(::Bugsnag).to have_received(:deliver_notification).once
end

describe "notify's resulting payload" do
describe "notifies resulting payload" do
subject(:notify_report) do
report = nil

17 changes: 17 additions & 0 deletions spec/support/bugsnag_helpers.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
module BugsnagHelpers
shared_examples "sends_a_bugsnag_notification" do
it do
allow(::Bugsnag).to receive(:deliver_notification)
subject
expect(::Bugsnag).to have_received(:deliver_notification).once
end
end

shared_examples "does_not_send_a_bugsnag_notification" do
it do
allow(::Bugsnag).to receive(:deliver_notification)
subject
expect(::Bugsnag).not_to have_received(:deliver_notification)
end
end
end

0 comments on commit 64814ec

Please sign in to comment.