Chr*_*ugh 19 ruby rspec ruby-on-rails resque resque-retry
我正在尝试编写一个测试resque-retry的重试功能的规范,我似乎无法让测试正确地命中binding.pry.有没有办法使用rspec 3测试此功能,以便我可以验证它们是否按预期运行?
这是一个请求规范,我试图通过fixtures模拟一个实时请求,但无论我尝试什么,我似乎无法得到重试的工作.
gem 'resque', require: 'resque/server'
gem 'resque-web', require: 'resque_web'
gem 'resque-scheduler'
gem 'resque-retry'
gem 'resque-lock-timeout'
Run Code Online (Sandbox Code Playgroud)
我正在使用resque_rspec,并尝试此测试策略.
部分规格
it 'retries it' do
stub_request(:any, /.*api.bigcartel.*/).to_return(body: '{}', status: 200)
@order_shipped_json['order']['originator_id'] = @provider_order
post "/hook/shops/#{@shop.id}", @order_shipped_json.to_json, format: :json
ResqueSpec.perform_all(queue_name)
???
end
Run Code Online (Sandbox Code Playgroud)
队列工作
class QueueHook
extend Resque::Plugins::LockTimeout
extend Resque::Plugins::Retry
extend QueueLock
extend QueueLogger
@queue = AppSettings.queues[:hook_queue_name].to_sym
@lock_timeout = 600
@retry_exceptions = [QueueError::LockFailed]
@retry_limit = 600
@retry_delay = 1
class << self
def perform(web_hook_payload_id, _whiplash_customer_id)
ActiveRecord::Base.clear_active_connections!
@web_hook_payload = WebHookPayload.find(web_hook_payload_id)
klass_constructor
@hook.process_event
end
def identifier(_web_hook_payload_id, whiplash_customer_id)
"lock:integration_hook:#{whiplash_customer_id}"
end
def after_perform_delete_webhook(_web_hook_payload_id, _whiplash_customer_id)
@web_hook_payload.destroy
end
private
...
end
end
Run Code Online (Sandbox Code Playgroud)
队列作业模块
module QueueLogger
def before_perform_log_job(*args)
Rails.logger.info "[Resque][#{self}] running with #{args.inspect}..."
end
def on_failure_log_job(*args)
message = "[Resque][#{self}] failed with #{args.inspect}..."
run_counters
Rails.logger.info message_builder(message)
end
private
def run_counters
@num_attempts += retry_attempt
@all_attempts += retry_limit
end
def message_builder(message)
return message unless @num_attempts
return message += " Retrying (attempt ##{@num_attempts + 1})" if @num_attempts < @all_attempts
message += ' Giving up.'
message
end
end
module QueueLock
def loner_enqueue_failed(*args)
Rails.logger.info "[Resque][#{self}] is already enqueued: #{args.inspect}..."
end
def lock_failed(*)
raise QueueError::LockFailed
end
end
Run Code Online (Sandbox Code Playgroud)
小智 1
因此,您想要测试重试的特定失败来自于您实现的这个钩子。
def lock_failed(*)
raise QueueError::LockFailed
end
Run Code Online (Sandbox Code Playgroud)
我们需要触发这个。这是它在插件中使用的地方。由于您使用了锁定超时,看起来我们想要存根.acquire_lock_algorithm!
。这是很危险的,因为这个方法是插件内部 api 的一部分。升级插件时请记住这一点。
it 'retries it' do
stub_request(:any, /.*api.bigcartel.*/).to_return(body: '{}', status: 200)
allow(QueueHook).to receive(:acquire_lock_algorithm!).and_return(false, true)
@order_shipped_json['order']['originator_id'] = @provider_order
post "/hook/shops/#{@shop.id}", @order_shipped_json.to_json, format: :json
ResqueSpec.perform_all(queue_name)
end
Run Code Online (Sandbox Code Playgroud)
这个规范现在应该失败了Failure/Error: raise QueueError::LockFailed
。既然这是预期的,我们就可以设定一个期望。
it 'retries it' do
stub_request(:any, /.*api.bigcartel.*/).to_return(body: '{}', status: 200)
allow(QueueHook).to receive(:acquire_lock_algorithm!).and_return(false, true)
@order_shipped_json['order']['originator_id'] = @provider_order
post "/hook/shops/#{@shop.id}", @order_shipped_json.to_json, format: :json
expect {
ResqueSpec.perform_all(queue_name)
}.to raise_error(QueueError::LockFailed)
end
Run Code Online (Sandbox Code Playgroud)
除非您已设置,否则规范现在应该已通过ResqueSpec.inline = true
。如果您已针对此规范将其设置为 false。它将更容易遵循。
如果 resque-retry 正在工作,那么作业失败应该会导致作业重新排队到 ResqueSpec。我们可以为此添加一个期望。expect(ResqueSpec.queues[queue_name]).to be_present
。不是我们可以再次运行作业。我们将第二个返回值模拟acquire_lock_algorithm!
为 true,因此这次作业应该会成功。
由于我们想测试计数器,让我们为它们添加阅读器
module QueueLogger
attr_reader :all_attempts, :num_attempts
end
Run Code Online (Sandbox Code Playgroud)
然后完成规格...
it 'retries it' do
stub_request(:any, /.*api.bigcartel.*/).to_return(body: '{}', status: 200)
allow(QueueHook).to receive(:acquire_lock_algorithm!).and_return(false, true)
@order_shipped_json['order']['originator_id'] = @provider_order
post "/hook/shops/#{@shop.id}", @order_shipped_json.to_json, format: :json
# Failing
expect {
ResqueSpec.perform_all(queue_name)
}.to raise_error(QueueError::LockFailed)
expect(ResqueSpec.queues[queue_name]).to be_present
# Retrying
ResqueSpec.perform_all(queue_name)
expect(QueueHook.num_attempts).to eq(2)
... # Whatever else you want to test.
end
Run Code Online (Sandbox Code Playgroud)
如果您想专门测试日志记录,您可以对它们进行存根并设置有关它们调用内容的期望。应该可以了,我有一个在我自己的机器上运行的简化版本。如果没有,我们可能需要了解您的测试和 Resque 配置的详细信息。