Skip to content

Commit 135e299

Browse files
authored
RUBY-3079 Propagate Original Error for Write Errors Labeled NoWritesPerformed (#2616)
* RUBY-3079 Propagate Original Error for Write Errors Labeled NoWritesPerformed * Update spec/integration/retryable_writes_errors_spec.rb * RUBY-3079 fix test description
1 parent 06f654c commit 135e299

File tree

2 files changed

+58
-1
lines changed

2 files changed

+58
-1
lines changed

lib/mongo/retryable.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -499,7 +499,7 @@ def retry_write(original_error, txn_num, context:, &block)
499499
raise e
500500
rescue Error::OperationFailure => e
501501
e.add_note('modern retry')
502-
if e.label?('RetryableWriteError')
502+
if e.label?('RetryableWriteError') && !e.label?('NoWritesPerformed')
503503
e.add_note('attempt 2')
504504
raise e
505505
else

spec/integration/retryable_writes_errors_spec.rb

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,4 +31,61 @@
3131
end
3232
end
3333
end
34+
35+
context "when encountering a NoWritesPerformed error after an error with a RetryableWriteError label" do
36+
require_topology :replica_set
37+
require_fail_command
38+
39+
let(:failpoint1) do
40+
{
41+
configureFailPoint: "failCommand",
42+
mode: { times: 1 },
43+
data: {
44+
writeConcernError: {
45+
code: 91,
46+
errorLabels: ["RetryableWriteError"],
47+
},
48+
failCommands: ["insert"],
49+
}
50+
}
51+
end
52+
53+
let(:failpoint2) do
54+
{
55+
configureFailPoint: "failCommand",
56+
mode: { times: 1 },
57+
data: {
58+
errorCode: 10107,
59+
errorLabels: ["RetryableWriteError", "NoWritesPerformed"],
60+
failCommands: ["insert"],
61+
},
62+
}
63+
end
64+
65+
let(:subscriber) { Mrss::EventSubscriber.new }
66+
67+
before do
68+
authorized_client.subscribe(Mongo::Monitoring::COMMAND, subscriber)
69+
authorized_client.use(:admin).command(failpoint1)
70+
71+
expect(authorized_collection).to receive(:retry_write).once.and_wrap_original do |m, *args, &block|
72+
expect(args.first.code).to eq(91)
73+
authorized_client.use(:admin).command(failpoint2)
74+
m.call(*args, &block)
75+
end
76+
end
77+
78+
after do
79+
authorized_client.use(:admin).command({
80+
configureFailPoint: "failCommand",
81+
mode: "off",
82+
})
83+
end
84+
85+
it "returns the original error" do
86+
expect do
87+
authorized_collection.insert_one(x: 1)
88+
end.to raise_error(Mongo::Error::OperationFailure, /\[91\]/)
89+
end
90+
end
3491
end

0 commit comments

Comments
 (0)