我有这两个示例类,我想编写一个第一次运行 PaymentCheckJob 的 rspec,如果 payment_type == 'ticket',我想检查它是否将另一个 sidekiq 作业排入队列
class ApplicationJob
include Sidekiq::Job
sidekiq_options retry: 1
def perform(*args)
# Do something
end
end
class PaymentCheckJob < ApplicationJob
def perform(args = '{}')
args = JSON.parse(args)
invoice_id = args['invoice_id']
if invoice.payment_type == 'ticket'
::PaymentCheckJob.perform_at(1.hour.from_now, { 'invoice_id': invoice.id }.to_json)
# ::PaymentCheckJob.perform_in(3600, { 'invoice_id': invoice.id }.to_json)
else
invoice.payed_at = Time.now
end
end
end
您可以存根此方法,编写两个不同的上下文:作业排队时和未排队时
类似这样的事情
require 'rails_helper'
RSpec.describe PaymentCheckJob, type: :job do
describe '#perform' do
subject(:perform_job) { described_class.new.perform(invoice_id: invoice.id) }
let(:invoice) { Invoice.create(payment_type: payment_type) }
before { allow(described_class).to receive(:perform_at) }
context 'when invoice is ticket' do
let(:payment_type) { 'ticket' }
it 'enqueues another PaymentCheckJob' do
perform_job
expect(described_class).to have_received(:perform_at)
end
end
context 'when invoice is not ticket' do
let(:payment_type) { 'not_ticket' }
it 'does not enqueue another PaymentCheckJob' do
perform_job
expect(described_class).not_to have_received(:perform_at)
end
end
end
end
您还可以检查作业大小,例如
expect { perform_job }.to change { PaymentCheckJob.jobs.size }.by(1)
expect { perform_job }.not_to change { PaymentCheckJob.jobs.size }
但我不确定从一项工作调用另一项工作是个好主意。也许您可以使用 cron 安排此作业(例如每 5 分钟 1 次),而不是传递一些参数,而是在作业主体内获取一批这些发票(例如像
Invoice.not_processed
这样的范围)。要排除竞争条件,您可以锁定这些发票以进行更新。另外,为了确保没有两个作业同时运行,请使用建议锁定(互斥锁)锁定执行方法的主体。当然,如果需要的话还可以更新发票。在这种情况下,您将更多地管理流程,并且作业不会以某种方式混乱地相互调用。我也这么认为