mongo 2.11.0 → 2.11.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/lib/mongo/retryable.rb +33 -8
- data/lib/mongo/version.rb +1 -1
- data/spec/integration/retryable_errors_spec.rb +203 -38
- data/spec/integration/retryable_writes_spec.rb +36 -36
- data/spec/runners/sdam/verifier.rb +88 -0
- data/spec/spec_tests/sdam_monitoring_spec.rb +9 -4
- data/spec/support/sdam_monitoring.rb +0 -115
- data/spec/support/spec_config.rb +1 -1
- metadata +609 -607
- metadata.gz.sig +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 33db1e0c2cfe7d7de3da0fbc3b24deac1ab01c0ad3cfc07239616bda20bd3e21
|
4
|
+
data.tar.gz: 6923e1d8fff7313a7f1a5a73e5a23fcebc6fa9b2b3d083e7f7468928ff2d76f1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 415ae16f9f26a04e7ed9d9d29f264f2632a8cfca230849a11152f8bc62a722aa4a7e600ca5db217e26e695ca2b270a54973bb9c339af67f1f3880c67ed917cc4
|
7
|
+
data.tar.gz: '058ec4695e331e142f99feee1a59082494ed91e80d55490985e8eee650f1d94ba767d581ea08180ccff18c93300642ea59ca91dc1fe44da6771fd4ca2a94d27f'
|
checksums.yaml.gz.sig
CHANGED
Binary file
|
data.tar.gz.sig
CHANGED
Binary file
|
data/lib/mongo/retryable.rb
CHANGED
@@ -119,7 +119,12 @@ module Mongo
|
|
119
119
|
legacy_read_with_retry(session, server_selector, &block)
|
120
120
|
else
|
121
121
|
server = select_server(cluster, server_selector, session)
|
122
|
-
|
122
|
+
begin
|
123
|
+
yield server
|
124
|
+
rescue Error::SocketError, Error::SocketTimeoutError, Error::OperationFailure => e
|
125
|
+
e.add_note('retries disabled')
|
126
|
+
raise e
|
127
|
+
end
|
123
128
|
end
|
124
129
|
end
|
125
130
|
|
@@ -214,12 +219,14 @@ module Mongo
|
|
214
219
|
begin
|
215
220
|
yield(server, txn_num, false)
|
216
221
|
rescue Error::SocketError, Error::SocketTimeoutError => e
|
222
|
+
e.add_note('modern retry')
|
217
223
|
e.add_note("attempt 1")
|
218
224
|
if session.in_transaction? && !ending_transaction
|
219
225
|
raise e
|
220
226
|
end
|
221
227
|
retry_write(e, session, txn_num, &block)
|
222
228
|
rescue Error::OperationFailure => e
|
229
|
+
e.add_note('modern retry')
|
223
230
|
e.add_note("attempt 1")
|
224
231
|
if e.unsupported_retryable_write?
|
225
232
|
raise_unsupported_error(e)
|
@@ -250,7 +257,12 @@ module Mongo
|
|
250
257
|
def nro_write_with_retry(session, write_concern, &block)
|
251
258
|
if session && session.client.options[:retry_writes]
|
252
259
|
server = select_server(cluster, ServerSelector.primary, session)
|
253
|
-
|
260
|
+
begin
|
261
|
+
yield server
|
262
|
+
rescue Error::SocketError, Error::SocketTimeoutError, Error::OperationFailure => e
|
263
|
+
e.add_note('retries disabled')
|
264
|
+
raise e
|
265
|
+
end
|
254
266
|
else
|
255
267
|
legacy_write_with_retry(nil, session, &block)
|
256
268
|
end
|
@@ -280,7 +292,8 @@ module Mongo
|
|
280
292
|
server ||= select_server(cluster, ServerSelector.primary, session)
|
281
293
|
yield server
|
282
294
|
rescue Error::OperationFailure => e
|
283
|
-
e.add_note(
|
295
|
+
e.add_note('legacy retry')
|
296
|
+
e.add_note("attempt #{attempt}")
|
284
297
|
server = nil
|
285
298
|
if attempt > client.max_write_retries
|
286
299
|
raise e
|
@@ -298,18 +311,19 @@ module Mongo
|
|
298
311
|
private
|
299
312
|
|
300
313
|
def modern_read_with_retry(session, server_selector, &block)
|
301
|
-
attempt = 0
|
302
314
|
server = select_server(cluster, server_selector, session)
|
303
315
|
begin
|
304
316
|
yield server
|
305
317
|
rescue Error::SocketError, Error::SocketTimeoutError => e
|
306
|
-
e.add_note(
|
318
|
+
e.add_note('modern retry')
|
319
|
+
e.add_note("attempt 1")
|
307
320
|
if session.in_transaction?
|
308
321
|
raise e
|
309
322
|
end
|
310
323
|
retry_read(e, server_selector, session, &block)
|
311
324
|
rescue Error::OperationFailure => e
|
312
|
-
e.add_note(
|
325
|
+
e.add_note('modern retry')
|
326
|
+
e.add_note("attempt 1")
|
313
327
|
if session.in_transaction? || !e.write_retryable?
|
314
328
|
raise e
|
315
329
|
end
|
@@ -324,7 +338,8 @@ module Mongo
|
|
324
338
|
attempt += 1
|
325
339
|
yield server
|
326
340
|
rescue Error::SocketError, Error::SocketTimeoutError => e
|
327
|
-
e.add_note(
|
341
|
+
e.add_note('legacy retry')
|
342
|
+
e.add_note("attempt #{attempt}")
|
328
343
|
if attempt > client.max_read_retries || (session && session.in_transaction?)
|
329
344
|
raise e
|
330
345
|
end
|
@@ -332,7 +347,8 @@ module Mongo
|
|
332
347
|
server = select_server(cluster, server_selector, session)
|
333
348
|
retry
|
334
349
|
rescue Error::OperationFailure => e
|
335
|
-
e.add_note(
|
350
|
+
e.add_note('legacy retry')
|
351
|
+
e.add_note("attempt #{attempt}")
|
336
352
|
if e.retryable? && !(session && session.in_transaction?)
|
337
353
|
if attempt > client.max_read_retries
|
338
354
|
raise e
|
@@ -375,9 +391,11 @@ module Mongo
|
|
375
391
|
begin
|
376
392
|
yield server, true
|
377
393
|
rescue Error::SocketError, Error::SocketTimeoutError => e
|
394
|
+
e.add_note('modern retry')
|
378
395
|
e.add_note("attempt 2")
|
379
396
|
raise e
|
380
397
|
rescue Error::OperationFailure => e
|
398
|
+
e.add_note('modern retry')
|
381
399
|
unless e.write_retryable?
|
382
400
|
original_error.add_note("later retry failed: #{e.class}: #{e}")
|
383
401
|
raise original_error
|
@@ -385,6 +403,7 @@ module Mongo
|
|
385
403
|
e.add_note("attempt 2")
|
386
404
|
raise e
|
387
405
|
rescue => e
|
406
|
+
e.add_note('modern retry')
|
388
407
|
original_error.add_note("later retry failed: #{e.class}: #{e}")
|
389
408
|
raise original_error
|
390
409
|
end
|
@@ -398,15 +417,19 @@ module Mongo
|
|
398
417
|
# server unknown). Here we just need to wait for server selection.
|
399
418
|
server = select_server(cluster, ServerSelector.primary, session)
|
400
419
|
unless server.retry_writes?
|
420
|
+
# Do not need to add "modern retry" here, it should already be on
|
421
|
+
# the first exception.
|
401
422
|
original_error.add_note('did not retry because server selected for retry does not supoprt retryable writes')
|
402
423
|
raise original_error
|
403
424
|
end
|
404
425
|
log_retry(original_error, message: 'Write retry')
|
405
426
|
yield(server, txn_num, true)
|
406
427
|
rescue Error::SocketError, Error::SocketTimeoutError => e
|
428
|
+
e.add_note('modern retry')
|
407
429
|
e.add_note('attempt 2')
|
408
430
|
raise e
|
409
431
|
rescue Error::OperationFailure => e
|
432
|
+
e.add_note('modern retry')
|
410
433
|
if e.write_retryable?
|
411
434
|
e.add_note('attempt 2')
|
412
435
|
raise e
|
@@ -415,6 +438,8 @@ module Mongo
|
|
415
438
|
raise original_error
|
416
439
|
end
|
417
440
|
rescue => e
|
441
|
+
# Do not need to add "modern retry" here, it should already be on
|
442
|
+
# the first exception.
|
418
443
|
original_error.add_note("later retry failed: #{e.class}: #{e}")
|
419
444
|
raise original_error
|
420
445
|
end
|
data/lib/mongo/version.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
describe '
|
3
|
+
describe 'Failing retryable operations' do
|
4
4
|
# Requirement for fail point
|
5
5
|
min_server_fcv '4.0'
|
6
6
|
|
@@ -9,22 +9,12 @@ describe 'Retryable writes tests' do
|
|
9
9
|
end
|
10
10
|
|
11
11
|
let(:collection) do
|
12
|
-
client['retryable-
|
12
|
+
client['retryable-errors-spec']
|
13
13
|
end
|
14
14
|
|
15
|
-
context 'when
|
15
|
+
context 'when operation fails' do
|
16
16
|
require_topology :replica_set
|
17
17
|
|
18
|
-
let(:fail_point_command) do
|
19
|
-
{
|
20
|
-
configureFailPoint: 'failCommand',
|
21
|
-
mode: {times: 1},
|
22
|
-
data: {
|
23
|
-
failCommands: ['find'],
|
24
|
-
errorCode: 11600,
|
25
|
-
},
|
26
|
-
}
|
27
|
-
end
|
28
18
|
|
29
19
|
let(:clear_fail_point_command) do
|
30
20
|
{
|
@@ -40,11 +30,7 @@ describe 'Retryable writes tests' do
|
|
40
30
|
end
|
41
31
|
|
42
32
|
let(:collection) do
|
43
|
-
client['retryable-
|
44
|
-
end
|
45
|
-
|
46
|
-
let(:events) do
|
47
|
-
events = EventSubscriber.command_started_events('find')
|
33
|
+
client['retryable-errors-spec', read: {mode: :secondary_preferred}]
|
48
34
|
end
|
49
35
|
|
50
36
|
let(:first_server) do
|
@@ -59,41 +45,220 @@ describe 'Retryable writes tests' do
|
|
59
45
|
end
|
60
46
|
end
|
61
47
|
|
62
|
-
|
63
|
-
|
64
|
-
|
48
|
+
shared_context 'read operation' do
|
49
|
+
let(:fail_point_command) do
|
50
|
+
{
|
51
|
+
configureFailPoint: 'failCommand',
|
52
|
+
mode: {times: 1},
|
53
|
+
data: {
|
54
|
+
failCommands: ['find'],
|
55
|
+
errorCode: 11600,
|
56
|
+
},
|
57
|
+
}
|
65
58
|
end
|
66
59
|
|
67
|
-
|
60
|
+
let(:set_fail_point) do
|
61
|
+
client.cluster.servers_list.each do |server|
|
62
|
+
server.monitor.stop!
|
63
|
+
end
|
64
|
+
|
65
|
+
ClusterTools.instance.direct_client_for_each_server do |client|
|
66
|
+
client.use(:admin).database.command(fail_point_command)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
let(:operation_exception) do
|
71
|
+
set_fail_point
|
72
|
+
|
73
|
+
begin
|
74
|
+
collection.find(a: 1).to_a
|
75
|
+
rescue Mongo::Error::OperationFailure => exception
|
76
|
+
else
|
77
|
+
fail('Expected operation to fail')
|
78
|
+
end
|
79
|
+
|
80
|
+
puts exception.message
|
81
|
+
|
82
|
+
exception
|
83
|
+
end
|
84
|
+
|
85
|
+
let(:events) do
|
86
|
+
EventSubscriber.command_started_events('find')
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
shared_context 'write operation' do
|
91
|
+
let(:fail_point_command) do
|
92
|
+
{
|
93
|
+
configureFailPoint: 'failCommand',
|
94
|
+
mode: {times: 2},
|
95
|
+
data: {
|
96
|
+
failCommands: ['insert'],
|
97
|
+
errorCode: 11600,
|
98
|
+
},
|
99
|
+
}
|
100
|
+
end
|
101
|
+
|
102
|
+
let(:set_fail_point) do
|
68
103
|
client.use(:admin).database.command(fail_point_command)
|
69
104
|
end
|
70
105
|
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
106
|
+
let(:operation_exception) do
|
107
|
+
set_fail_point
|
108
|
+
|
109
|
+
begin
|
110
|
+
collection.insert_one(a: 1)
|
111
|
+
rescue Mongo::Error::OperationFailure => exception
|
112
|
+
else
|
113
|
+
fail('Expected operation to fail')
|
114
|
+
end
|
115
|
+
|
116
|
+
#puts exception.message
|
117
|
+
|
118
|
+
exception
|
119
|
+
end
|
120
|
+
|
121
|
+
let(:events) do
|
122
|
+
EventSubscriber.command_started_events('insert')
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
shared_examples_for 'failing retry' do
|
127
|
+
|
128
|
+
it 'indicates second attempt' do
|
129
|
+
expect(operation_exception.message).to include('attempt 2')
|
130
|
+
expect(operation_exception.message).not_to include('attempt 1')
|
131
|
+
expect(operation_exception.message).not_to include('attempt 3')
|
76
132
|
end
|
77
133
|
|
78
|
-
|
134
|
+
it 'publishes two events' do
|
79
135
|
|
80
|
-
|
81
|
-
|
136
|
+
expect(events.length).to eq(2)
|
137
|
+
end
|
82
138
|
end
|
83
139
|
|
84
|
-
|
85
|
-
|
140
|
+
shared_examples_for 'failing single attempt' do
|
141
|
+
|
142
|
+
it 'does not indicate attempt' do
|
143
|
+
expect(operation_exception.message).not_to include('attempt 1')
|
144
|
+
expect(operation_exception.message).not_to include('attempt 2')
|
145
|
+
expect(operation_exception.message).not_to include('attempt 3')
|
146
|
+
end
|
86
147
|
|
87
|
-
|
88
|
-
|
148
|
+
it 'publishes one event' do
|
149
|
+
|
150
|
+
expect(events.length).to eq(1)
|
151
|
+
end
|
89
152
|
end
|
90
153
|
|
91
|
-
|
92
|
-
|
154
|
+
shared_examples_for 'failing retry on the same server' do
|
155
|
+
it 'is reported on the server of the second attempt' do
|
156
|
+
expect(operation_exception.message).to include(second_server.address.seed)
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
shared_examples_for 'failing retry on a different server' do
|
161
|
+
it 'is reported on the server of the second attempt' do
|
162
|
+
expect(operation_exception.message).not_to include(first_server.address.seed)
|
163
|
+
expect(operation_exception.message).to include(second_server.address.seed)
|
164
|
+
end
|
93
165
|
|
94
|
-
|
166
|
+
it 'marks servers used in both attempts unknown' do
|
167
|
+
operation_exception
|
95
168
|
|
96
|
-
|
169
|
+
expect(first_server).to be_unknown
|
170
|
+
|
171
|
+
expect(second_server).to be_unknown
|
172
|
+
end
|
173
|
+
|
174
|
+
it 'publishes events for the different server addresses' do
|
175
|
+
|
176
|
+
expect(events.length).to eq(2)
|
177
|
+
expect(events.first.address.seed).not_to eq(events.last.address.seed)
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
shared_examples_for 'modern retry' do
|
182
|
+
it 'indicates modern retry' do
|
183
|
+
expect(operation_exception.message).to include('modern retry')
|
184
|
+
expect(operation_exception.message).not_to include('legacy retry')
|
185
|
+
expect(operation_exception.message).not_to include('retries disabled')
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
shared_examples_for 'legacy retry' do
|
190
|
+
it 'indicates legacy retry' do
|
191
|
+
expect(operation_exception.message).to include('legacy retry')
|
192
|
+
expect(operation_exception.message).not_to include('modern retry')
|
193
|
+
expect(operation_exception.message).not_to include('retries disabled')
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
shared_examples_for 'disabled retry' do
|
198
|
+
it 'indicates retries are disabled' do
|
199
|
+
expect(operation_exception.message).to include('retries disabled')
|
200
|
+
expect(operation_exception.message).not_to include('legacy retry')
|
201
|
+
expect(operation_exception.message).not_to include('modern retry')
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
context 'when read is retried and retry fails' do
|
206
|
+
include_context 'read operation'
|
207
|
+
|
208
|
+
context 'modern read retries' do
|
209
|
+
require_wired_tiger_on_36
|
210
|
+
|
211
|
+
let(:client) do
|
212
|
+
subscribed_client.with(retry_reads: true)
|
213
|
+
end
|
214
|
+
|
215
|
+
it_behaves_like 'failing retry'
|
216
|
+
it_behaves_like 'modern retry'
|
217
|
+
end
|
218
|
+
|
219
|
+
context 'legacy read retries' do
|
220
|
+
let(:client) do
|
221
|
+
subscribed_client.with(retry_reads: false, read_retry_interval: 0)
|
222
|
+
end
|
223
|
+
|
224
|
+
it_behaves_like 'failing retry'
|
225
|
+
it_behaves_like 'legacy retry'
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
229
|
+
context 'when read retries are disabled' do
|
230
|
+
let(:client) do
|
231
|
+
subscribed_client.with(retry_reads: false, max_read_retries: 0)
|
232
|
+
end
|
233
|
+
|
234
|
+
include_context 'read operation'
|
235
|
+
|
236
|
+
it_behaves_like 'failing single attempt'
|
237
|
+
it_behaves_like 'disabled retry'
|
238
|
+
end
|
239
|
+
|
240
|
+
context 'when write is retried and retry fails' do
|
241
|
+
include_context 'write operation'
|
242
|
+
|
243
|
+
context 'modern write retries' do
|
244
|
+
require_wired_tiger_on_36
|
245
|
+
|
246
|
+
let(:client) do
|
247
|
+
subscribed_client.with(retry_writes: true)
|
248
|
+
end
|
249
|
+
|
250
|
+
it_behaves_like 'failing retry'
|
251
|
+
it_behaves_like 'modern retry'
|
252
|
+
end
|
253
|
+
|
254
|
+
context 'legacy write' do
|
255
|
+
let(:client) do
|
256
|
+
subscribed_client.with(retry_writes: false)
|
257
|
+
end
|
258
|
+
|
259
|
+
it_behaves_like 'failing retry'
|
260
|
+
it_behaves_like 'legacy retry'
|
261
|
+
end
|
97
262
|
end
|
98
263
|
end
|
99
264
|
end
|