Skip to content

Commit 9b51d53

Browse files
Backpressure final touches (#3019)
1 parent 7bcb5ab commit 9b51d53

4 files changed

Lines changed: 34 additions & 13 deletions

File tree

lib/mongo/session.rb

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1408,10 +1408,16 @@ def backoff_would_exceed_deadline?(deadline, backoff_seconds)
14081408
end
14091409

14101410
# Implements makeTimeoutError(lastError) from the transactions-convenient-api spec.
1411-
# In CSOT mode raises TimeoutError with last_error's message included as a substring.
1411+
# In CSOT mode raises TimeoutError with last_error's message and labels copied.
14121412
# In non-CSOT mode re-raises last_error directly.
14131413
def make_timeout_error_from(last_error, timeout_message)
1414-
raise Mongo::Error::TimeoutError, "#{timeout_message}: #{last_error}" if @with_transaction_timeout_ms
1414+
if @with_transaction_timeout_ms
1415+
timeout_error = Mongo::Error::TimeoutError.new("#{timeout_message}: #{last_error}")
1416+
if last_error.respond_to?(:labels)
1417+
last_error.labels.each { |label| timeout_error.add_label(label) }
1418+
end
1419+
raise timeout_error
1420+
end
14151421

14161422
raise last_error
14171423
end

spec/mongo/retryable/retryable_writes_error_propagation_prose_spec.rb

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -132,8 +132,11 @@
132132
# some errors with NoWritesPerformed and some without.
133133
context 'Case 3: mixed errors with and without NoWritesPerformed' do
134134
it 'returns the error without NoWritesPerformed (91)' do
135-
# Step 2: Via CommandFailedEvent, configure a fail point with
136-
# error code 91 and NoWritesPerformed for subsequent retries.
135+
# Step 3 (set up before step 2 so the listener is active when
136+
# the first failure occurs): Via CommandFailedEvent, configure
137+
# a fail point with error code 91 and NoWritesPerformed for
138+
# subsequent retries. Configure only if the failed event is for
139+
# the first error configured in step 2.
137140
failpoint_set = false
138141
subscriber = Mrss::EventSubscriber.new
139142
client.subscribe(Mongo::Monitoring::COMMAND, subscriber)
@@ -154,8 +157,9 @@
154157
end
155158
end
156159

157-
# Step 3: Configure initial fail point with error code 91
158-
# WITHOUT NoWritesPerformed.
160+
# Step 2: Configure initial fail point with error code 91
161+
# (ShutdownInProgress) with RetryableError and
162+
# SystemOverloadedError labels, without NoWritesPerformed.
159163
admin_client.command(
160164
configureFailPoint: 'failCommand',
161165
mode: { times: 1 },

spec/mongo/session/with_transaction_timeout_spec.rb

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -120,10 +120,13 @@ def make_commit_overload_error
120120
context 'when callback raises TransientTransactionError and retry timeout is exceeded' do
121121
let(:transient_error) { make_transient_error }
122122

123-
it 'propagates the error as TimeoutError including the transient error message' do
123+
it 'propagates the error as TimeoutError with the same labels as the wrapped error' do
124124
with_expired_deadline_after(initial_calls: 1) do
125125
ex = expect { session.with_transaction(timeout_ms: 1) { raise transient_error } }
126-
ex.to raise_error(Mongo::Error::TimeoutError) { |e| expect(e.message).to include(transient_error.message) }
126+
ex.to raise_error(Mongo::Error::TimeoutError) do |e|
127+
expect(e.message).to include(transient_error.message)
128+
expect(e.labels).to match_array(transient_error.labels)
129+
end
127130
end
128131
end
129132
end
@@ -133,14 +136,17 @@ def make_commit_overload_error
133136

134137
before { allow(session).to receive(:commit_transaction) { raise commit_error } }
135138

136-
it 'propagates the error as TimeoutError including the commit error message' do
139+
it 'propagates the error as TimeoutError with the same labels as the wrapped error' do
137140
with_expired_deadline_after(initial_calls: 2) do
138141
ex = expect do
139142
session.with_transaction(timeout_ms: 1) do
140143
session.instance_variable_set(:@state, Mongo::Session::TRANSACTION_IN_PROGRESS_STATE)
141144
end
142145
end
143-
ex.to raise_error(Mongo::Error::TimeoutError) { |e| expect(e.message).to include(commit_error.message) }
146+
ex.to raise_error(Mongo::Error::TimeoutError) do |e|
147+
expect(e.message).to include(commit_error.message)
148+
expect(e.labels).to match_array(commit_error.labels)
149+
end
144150
end
145151
end
146152
end
@@ -150,14 +156,17 @@ def make_commit_overload_error
150156

151157
before { allow(session).to receive(:commit_transaction) { raise commit_error } }
152158

153-
it 'propagates the error as TimeoutError including the commit error message' do
159+
it 'propagates the error as TimeoutError with the same labels as the wrapped error' do
154160
with_expired_deadline_after(initial_calls: 2) do
155161
ex = expect do
156162
session.with_transaction(timeout_ms: 1) do
157163
session.instance_variable_set(:@state, Mongo::Session::TRANSACTION_IN_PROGRESS_STATE)
158164
end
159165
end
160-
ex.to raise_error(Mongo::Error::TimeoutError) { |e| expect(e.message).to include(commit_error.message) }
166+
ex.to raise_error(Mongo::Error::TimeoutError) do |e|
167+
expect(e.message).to include(commit_error.message)
168+
expect(e.labels).to match_array(commit_error.labels)
169+
end
161170
end
162171
end
163172
end

spec/spec_tests/data/sdam/errors/error_handling_handshake.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,9 @@ phases:
3737
type: timeout
3838
outcome: *outcome
3939

40-
- description: Mark server unknown on network timeout application error (beforeHandshakeCompletes)
40+
- description: Ignore network timeout application error (beforeHandshakeCompletes)
41+
# The test runner may need to add the SystemOverloadedError label for the pre-handshake network timeout.
42+
# The SystemOverloadedError label causes the error to be ignored.
4143
applicationErrors:
4244
- address: a:27017
4345
when: beforeHandshakeCompletes

0 commit comments

Comments
 (0)