假设有一个使用processA
的服务,这是一个幂等进程,当调用它时,期望它找到或创建一个Payment
记录并返回它。
class processA
attr_reader :payment
def initialize(operation_id)
@payment = Payment.find_or_initialize_by(operation_id: operation_id)
end
def call
update_payment_attributes
payment.save!
end
private
def update_payment_attributes
# assign/update payment attributes
end
end
假设processA
是幂等的,processA
会查找与给定operation_id
匹配的现有记录,但如果没有找到,则会示例化一个具有所述属性的记录,保存并返回该记录。
如果没有找到与传递的operation_id
匹配的Payment
记录,并且开始创建新的Payment
,则processB
可能会发生竞争条件,这可能会创建一个具有相同operation_id
的Payment
,其速度可能比processA
完成任务的速度更快。
如果发生这种情况,当新的Payment
保存在processA
中时,由于某些模型约束阻止两个Payment
记录具有相同的operation_id
,因此会引发ActiveRecord::RecordNotUnique
错误。
问题:
我在服务processAConsumer
中有一些重试逻辑,所以在processA
引发错误的情况下,它只是被第二次调用,这样processB
创建的Payment
就会被找到并返回。
class processAConsumer
def call(operation_id)
begin
retries ||= 0
payment = processA.new(operation_id).call
rescue PG::UniqueViolation, ActiveRecord::RecordNotUnique
retry if (retries += 1) < 3
end
end
end
使用Minitest,我如何测试这个重试逻辑?有没有办法将第一个processA
#call
存根,这样它就会引发错误并启动重试逻辑?
我尝试过不同的东西,看起来像这样,没有成功:
test "retry logic should succeed" do
processA.any_instance.expects(:call) do
1.times do
raise PG::UniqueViolation, ActiveRecord::RecordNotUnique
end
end
response = processAConsumer.call(123)
assert response.success? # fails because the retry logic is not kicking in.
end
1条答案
按热度按时间0ejtzxu11#
对于任何想知道的人,这是我用来测试重试逻辑的:
这使得第一个
processA
#call
返回PG::UniqueViolation
错误。重试逻辑启动,第二次调用processA``#call
时返回Payment
的示例。