В последние несколько дней я безуспешно пытался протестировать этот метод.
Еще одна вещь, которую я хотел бы сделать - это rescue
ошибка, которая всплывает после последней попытки повторения.
Пожалуйста, смотрите мои комментарии и фрагменты кода ниже.
Исходный код для retry_on здесь также для контекста.
Вот пример кода и тесты:
my_job.rb
retry_on Exception, wait: 2.hours, attempts: 3 do |job, exception|
# some kind of rescue here after job.exceptions == 3
# then notify Bugsnag of failed final attempt.
end
def perform(an_object)
an_object.does_something
end
my_spec.rb
it 'receives retry_on 3 times' do
perform_enqueued_jobs do
expect(AnObject).to receive(:does_something).and_raise { Exception }.exactly(3).times
expect(MyJob).to receive(:retry_on).with(wait: 2.hours, attempts: 3).exactly(3).times
MyJob.perform_later(an_object)
end
assert_performed_jobs 3
end
Ответ теста на неудачу:
1) MyJob.perform receives retry_on 3 times
Failure/Error: expect(job).to receive(:retry_on).with(wait: 4.hours, attempts: 3).exactly(3).times
(MyJob (class)).retry_on({:wait=>2 hours, :attempts=>3})
expected: 3 times with arguments: ({:wait=>2 hours, :attempts=>3})
received: 0 times
# ./spec/jobs/my_job_spec.rb:38:in 'block (4 levels) in <top (required)>'
# ./spec/rails_helper.rb:48:in 'block (3 levels) in <top (required)>'
# ./spec/rails_helper.rb:47:in 'block (2 levels) in <top (required)>'
Я также пытался сделать работу двойной и заглушить метод retry_on
, и это тоже не работает.
Я также попытался использовать Timecop для ускорения пересылки времени ожидания, и тесты по-прежнему не выполняются:
my_spec.rb
it 'receives retry_on 3 times' do
perform_enqueued_jobs do
expect(AnObject).to receive(:does_something).and_raise { Exception }.exactly(3).times
Timecop.freeze(Time.now + 8.hours) do
expect(MyJob).to receive(:retry_on).with(wait: 2.hours, attempts: 3).exactly(3).times
end
MyJob.perform_later(an_object)
end
assert_performed_jobs 3
end
Это метод класса ActiveJob
, и я подтвердил это в терминале byebug
, что это так и есть с моим классом работы.
Разве этот тест не должен работать? Он ожидает, что класс получит метод класса с определенными аргументами. Мой byebug
также получает удар, когда я помещаю его в блок retry_on
, поэтому я знаю, что метод вызывается несколько раз.
Это почти как если бы он был вызван в другом классе, что очень запутанно, и я не думаю, что это так, но я в конце своей веревки с этим.
Я почти решил эту проблему, отделив свои тесты от тестирования самой логики рельсов retry_on
до тестирования моей бизнес-логики вокруг нее. Этот способ также лучше в случае, когда рельсы когда-либо изменяют логику retry_on
.
ОДНАКО, это НЕ работает для более чем одного теста. Если вы используете это более чем в одном случае, последний тест будет прерван и он скажет, что выполнил больше заданий, чем ожидалось.
my_spec.rb
it 'receives retry_on 3 times' do
perform_enqueued_jobs do
allow(AnObject).to receive(:does_something).and_raise { Exception }
expect(AnObject).to receive(:does_something).exactly(3).times
expect(Bugsnag).to receive(:notify).with(Exception).once
MyJob.perform_later(an_object)
end
assert_performed_jobs 3
end
my_job.rb
retry_on Exception, wait: , attempts: 3 do |job, exception|
Bugsnag.notify(exception)
end
def perform(an_object)
an_object.does_something
end
Любая помощь/понимание этого будет принята с благодарностью.
Также хотелось бы получить рекомендацию о том, как обрабатывать всплывающее исключение после максимальных попыток. Я подумываю о том, чтобы вызвать ошибку в блоке retry_on
, а затем вызвать discard_on
триггер для возникшей ошибки.
Спасибо, замечательное сообщество Qaru!