mongo 2.10.2 → 2.10.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (35) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/lib/mongo/collection/view/readable.rb +2 -2
  5. data/lib/mongo/cursor/builder/get_more_command.rb +4 -1
  6. data/lib/mongo/cursor/builder/kill_cursors_command.rb +16 -5
  7. data/lib/mongo/cursor/builder/op_get_more.rb +2 -2
  8. data/lib/mongo/cursor/builder/op_kill_cursors.rb +17 -5
  9. data/lib/mongo/error/operation_failure.rb +3 -3
  10. data/lib/mongo/protocol/get_more.rb +2 -1
  11. data/lib/mongo/protocol/kill_cursors.rb +6 -13
  12. data/lib/mongo/protocol/serializers.rb +10 -4
  13. data/lib/mongo/retryable.rb +34 -9
  14. data/lib/mongo/version.rb +1 -1
  15. data/mongo.gemspec +1 -1
  16. data/spec/integration/cursor_reaping_spec.rb +1 -1
  17. data/spec/integration/get_more_spec.rb +32 -0
  18. data/spec/integration/retryable_errors_spec.rb +265 -0
  19. data/spec/integration/retryable_writes_spec.rb +36 -36
  20. data/spec/mongo/bulk_write_spec.rb +2 -2
  21. data/spec/mongo/cursor/builder/get_more_command_spec.rb +4 -2
  22. data/spec/mongo/cursor/builder/op_get_more_spec.rb +4 -2
  23. data/spec/mongo/cursor_spec.rb +3 -3
  24. data/spec/mongo/retryable_spec.rb +31 -52
  25. data/spec/runners/sdam/verifier.rb +88 -0
  26. data/spec/spec_tests/retryable_reads_spec.rb +31 -0
  27. data/spec/spec_tests/sdam_monitoring_spec.rb +9 -4
  28. data/spec/support/cluster_tools.rb +4 -3
  29. data/spec/support/command_monitoring.rb +5 -0
  30. data/spec/support/event_subscriber.rb +7 -0
  31. data/spec/support/sdam_monitoring.rb +0 -115
  32. data/spec/support/spec_config.rb +1 -1
  33. data/spec/support/utils.rb +1 -1
  34. metadata +10 -4
  35. metadata.gz.sig +0 -0
@@ -0,0 +1,265 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'Failing retryable operations' do
4
+ # Requirement for fail point
5
+ min_server_fcv '4.0'
6
+
7
+ let(:client) do
8
+ subscribed_client
9
+ end
10
+
11
+ let(:collection) do
12
+ client['retryable-errors-spec']
13
+ end
14
+
15
+ context 'when operation fails' do
16
+ require_topology :replica_set
17
+
18
+
19
+ let(:clear_fail_point_command) do
20
+ {
21
+ configureFailPoint: 'failCommand',
22
+ mode: 'off',
23
+ }
24
+ end
25
+
26
+ after do
27
+ ClusterTools.instance.direct_client_for_each_server do |client|
28
+ client.use(:admin).database.command(clear_fail_point_command)
29
+ end
30
+ end
31
+
32
+ let(:collection) do
33
+ client['retryable-errors-spec', read: {mode: :secondary_preferred}]
34
+ end
35
+
36
+ let(:first_server) do
37
+ client.cluster.servers_list.detect do |server|
38
+ server.address.seed == events.first.address.seed
39
+ end
40
+ end
41
+
42
+ let(:second_server) do
43
+ client.cluster.servers_list.detect do |server|
44
+ server.address.seed == events.last.address.seed
45
+ end
46
+ end
47
+
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
+ }
58
+ end
59
+
60
+ let(:set_fail_point) do
61
+ client.cluster.servers_list.each do |server|
62
+ server.scan!
63
+ server.monitor.stop!
64
+ end
65
+
66
+ ClusterTools.instance.direct_client_for_each_server do |client|
67
+ client.use(:admin).database.command(fail_point_command)
68
+ end
69
+ end
70
+
71
+ let(:operation_exception) do
72
+ set_fail_point
73
+
74
+ begin
75
+ collection.find(a: 1).to_a
76
+ rescue Mongo::Error::OperationFailure => exception
77
+ else
78
+ fail('Expected operation to fail')
79
+ end
80
+
81
+ puts exception.message
82
+
83
+ exception
84
+ end
85
+
86
+ let(:events) do
87
+ EventSubscriber.command_started_events('find')
88
+ end
89
+ end
90
+
91
+ shared_context 'write operation' do
92
+ let(:fail_point_command) do
93
+ {
94
+ configureFailPoint: 'failCommand',
95
+ mode: {times: 2},
96
+ data: {
97
+ failCommands: ['insert'],
98
+ errorCode: 11600,
99
+ },
100
+ }
101
+ end
102
+
103
+ let(:set_fail_point) do
104
+ client.use(:admin).database.command(fail_point_command)
105
+ end
106
+
107
+ let(:operation_exception) do
108
+ set_fail_point
109
+
110
+ begin
111
+ collection.insert_one(a: 1)
112
+ rescue Mongo::Error::OperationFailure => exception
113
+ else
114
+ fail('Expected operation to fail')
115
+ end
116
+
117
+ #puts exception.message
118
+
119
+ exception
120
+ end
121
+
122
+ let(:events) do
123
+ EventSubscriber.command_started_events('insert')
124
+ end
125
+ end
126
+
127
+ shared_examples_for 'failing retry' do
128
+
129
+ it 'indicates second attempt' do
130
+ expect(operation_exception.message).to include('attempt 2')
131
+ expect(operation_exception.message).not_to include('attempt 1')
132
+ expect(operation_exception.message).not_to include('attempt 3')
133
+ end
134
+
135
+ it 'publishes two events' do
136
+
137
+ expect(events.length).to eq(2)
138
+ end
139
+ end
140
+
141
+ shared_examples_for 'failing single attempt' do
142
+
143
+ it 'does not indicate attempt' do
144
+ expect(operation_exception.message).not_to include('attempt 1')
145
+ expect(operation_exception.message).not_to include('attempt 2')
146
+ expect(operation_exception.message).not_to include('attempt 3')
147
+ end
148
+
149
+ it 'publishes one event' do
150
+
151
+ expect(events.length).to eq(1)
152
+ end
153
+ end
154
+
155
+ shared_examples_for 'failing retry on the same server' do
156
+ it 'is reported on the server of the second attempt' do
157
+ expect(operation_exception.message).to include(second_server.address.seed)
158
+ end
159
+ end
160
+
161
+ shared_examples_for 'failing retry on a different server' do
162
+ it 'is reported on the server of the second attempt' do
163
+ expect(operation_exception.message).not_to include(first_server.address.seed)
164
+ expect(operation_exception.message).to include(second_server.address.seed)
165
+ end
166
+
167
+ it 'marks servers used in both attempts unknown' do
168
+ operation_exception
169
+
170
+ expect(first_server).to be_unknown
171
+
172
+ expect(second_server).to be_unknown
173
+ end
174
+
175
+ it 'publishes events for the different server addresses' do
176
+
177
+ expect(events.length).to eq(2)
178
+ expect(events.first.address.seed).not_to eq(events.last.address.seed)
179
+ end
180
+ end
181
+
182
+ shared_examples_for 'modern retry' do
183
+ it 'indicates modern retry' do
184
+ expect(operation_exception.message).to include('modern retry')
185
+ expect(operation_exception.message).not_to include('legacy retry')
186
+ expect(operation_exception.message).not_to include('retries disabled')
187
+ end
188
+ end
189
+
190
+ shared_examples_for 'legacy retry' do
191
+ it 'indicates legacy retry' do
192
+ expect(operation_exception.message).to include('legacy retry')
193
+ expect(operation_exception.message).not_to include('modern retry')
194
+ expect(operation_exception.message).not_to include('retries disabled')
195
+ end
196
+ end
197
+
198
+ shared_examples_for 'disabled retry' do
199
+ it 'indicates retries are disabled' do
200
+ expect(operation_exception.message).to include('retries disabled')
201
+ expect(operation_exception.message).not_to include('legacy retry')
202
+ expect(operation_exception.message).not_to include('modern retry')
203
+ end
204
+ end
205
+
206
+ context 'when read is retried and retry fails' do
207
+ include_context 'read operation'
208
+
209
+ context 'modern read retries' do
210
+ require_wired_tiger_on_36
211
+
212
+ let(:client) do
213
+ subscribed_client.with(retry_reads: true)
214
+ end
215
+
216
+ it_behaves_like 'failing retry'
217
+ it_behaves_like 'modern retry'
218
+ end
219
+
220
+ context 'legacy read retries' do
221
+ let(:client) do
222
+ subscribed_client.with(retry_reads: false, read_retry_interval: 0)
223
+ end
224
+
225
+ it_behaves_like 'failing retry'
226
+ it_behaves_like 'legacy retry'
227
+ end
228
+ end
229
+
230
+ context 'when read retries are disabled' do
231
+ let(:client) do
232
+ subscribed_client.with(retry_reads: false, max_read_retries: 0)
233
+ end
234
+
235
+ include_context 'read operation'
236
+
237
+ it_behaves_like 'failing single attempt'
238
+ it_behaves_like 'disabled retry'
239
+ end
240
+
241
+ context 'when write is retried and retry fails' do
242
+ include_context 'write operation'
243
+
244
+ context 'modern write retries' do
245
+ require_wired_tiger_on_36
246
+
247
+ let(:client) do
248
+ subscribed_client.with(retry_writes: true)
249
+ end
250
+
251
+ it_behaves_like 'failing retry'
252
+ it_behaves_like 'modern retry'
253
+ end
254
+
255
+ context 'legacy write' do
256
+ let(:client) do
257
+ subscribed_client.with(retry_writes: false)
258
+ end
259
+
260
+ it_behaves_like 'failing retry'
261
+ it_behaves_like 'legacy retry'
262
+ end
263
+ end
264
+ end
265
+ end
@@ -102,22 +102,22 @@ describe 'Retryable writes integration tests' do
102
102
  end
103
103
 
104
104
  it 'does not retry writes' do
105
- expect {
105
+ expect do
106
106
  operation
107
- }.to raise_error(Mongo::Error::OperationFailure, /other error/)
107
+ end.to raise_error(Mongo::Error::OperationFailure, /other error/)
108
108
  expect(expectation).to eq(unsuccessful_retry_value)
109
109
  end
110
110
 
111
111
  it 'indicates server used for operation' do
112
- expect {
112
+ expect do
113
113
  operation
114
- }.to raise_error(Mongo::Error::OperationFailure, /on #{ClusterConfig.instance.primary_address_str}/)
114
+ end.to raise_error(Mongo::Error::OperationFailure, /on #{ClusterConfig.instance.primary_address_str}/)
115
115
  end
116
116
 
117
117
  it 'indicates first attempt' do
118
- expect {
118
+ expect do
119
119
  operation
120
- }.to raise_error(Mongo::Error::OperationFailure, /attempt 1/)
120
+ end.to raise_error(Mongo::Error::OperationFailure, /attempt 1/)
121
121
  end
122
122
  end
123
123
  end
@@ -144,9 +144,9 @@ describe 'Retryable writes integration tests' do
144
144
  end
145
145
 
146
146
  it 'does not retry writes and raises the original error' do
147
- expect {
147
+ expect do
148
148
  operation
149
- }.to raise_error(error)
149
+ end.to raise_error(error)
150
150
  expect(expectation).to eq(unsuccessful_retry_value)
151
151
  end
152
152
  end
@@ -158,9 +158,9 @@ describe 'Retryable writes integration tests' do
158
158
  end
159
159
 
160
160
  it 'does not retry writes and raises the original error' do
161
- expect {
161
+ expect do
162
162
  operation
163
- }.to raise_error(error)
163
+ end.to raise_error(error)
164
164
  expect(expectation).to eq(unsuccessful_retry_value)
165
165
  end
166
166
  end
@@ -172,9 +172,9 @@ describe 'Retryable writes integration tests' do
172
172
  end
173
173
 
174
174
  it 'does not retry writes and raises the original error' do
175
- expect {
175
+ expect do
176
176
  operation
177
- }.to raise_error(error)
177
+ end.to raise_error(error)
178
178
  expect(expectation).to eq(unsuccessful_retry_value)
179
179
  end
180
180
  end
@@ -211,22 +211,22 @@ describe 'Retryable writes integration tests' do
211
211
  end
212
212
 
213
213
  it 'raises the second error' do
214
- expect {
214
+ expect do
215
215
  operation
216
- }.to raise_error(second_error)
216
+ end.to raise_error(second_error)
217
217
  expect(expectation).to eq(unsuccessful_retry_value)
218
218
  end
219
219
 
220
220
  it 'indicates server used for operation' do
221
- expect {
221
+ expect do
222
222
  operation
223
- }.to raise_error(Mongo::Error, /on #{ClusterConfig.instance.primary_address_str}/)
223
+ end.to raise_error(Mongo::Error, /on #{ClusterConfig.instance.primary_address_str}/)
224
224
  end
225
225
 
226
226
  it 'indicates second attempt' do
227
- expect {
227
+ expect do
228
228
  operation
229
- }.to raise_error(Mongo::Error, /attempt 2/)
229
+ end.to raise_error(Mongo::Error, /attempt 2/)
230
230
  end
231
231
  end
232
232
 
@@ -237,9 +237,9 @@ describe 'Retryable writes integration tests' do
237
237
  end
238
238
 
239
239
  it 'raises the second error' do
240
- expect {
240
+ expect do
241
241
  operation
242
- }.to raise_error(second_error)
242
+ end.to raise_error(second_error)
243
243
  expect(expectation).to eq(unsuccessful_retry_value)
244
244
  end
245
245
  end
@@ -251,9 +251,9 @@ describe 'Retryable writes integration tests' do
251
251
  end
252
252
 
253
253
  it 'raises the second error' do
254
- expect {
254
+ expect do
255
255
  operation
256
- }.to raise_error(second_error)
256
+ end.to raise_error(second_error)
257
257
  expect(expectation).to eq(unsuccessful_retry_value)
258
258
  end
259
259
  end
@@ -265,9 +265,9 @@ describe 'Retryable writes integration tests' do
265
265
  end
266
266
 
267
267
  it 'does not retry writes and raises the first error' do
268
- expect {
268
+ expect do
269
269
  operation
270
- }.to raise_error(error)
270
+ end.to raise_error(error)
271
271
  expect(expectation).to eq(unsuccessful_retry_value)
272
272
  end
273
273
  end
@@ -279,28 +279,28 @@ describe 'Retryable writes integration tests' do
279
279
  end
280
280
 
281
281
  it 'raises the first error' do
282
- expect {
282
+ expect do
283
283
  operation
284
- }.to raise_error(error)
284
+ end.to raise_error(error)
285
285
  expect(expectation).to eq(unsuccessful_retry_value)
286
286
  end
287
287
 
288
288
  it 'indicates server used for operation' do
289
- expect {
289
+ expect do
290
290
  operation
291
- }.to raise_error(Mongo::Error, /on #{ClusterConfig.instance.primary_address_str}/)
291
+ end.to raise_error(Mongo::Error, /on #{ClusterConfig.instance.primary_address_str}/)
292
292
  end
293
293
 
294
294
  it 'indicates first attempt' do
295
- expect {
295
+ expect do
296
296
  operation
297
- }.to raise_error(Mongo::Error, /attempt 1/)
297
+ end.to raise_error(Mongo::Error, /attempt 1/)
298
298
  end
299
299
 
300
300
  it 'indicates retry was performed' do
301
- expect {
301
+ expect do
302
302
  operation
303
- }.to raise_error(Mongo::Error, /later retry failed: StandardError/)
303
+ end.to raise_error(Mongo::Error, /later retry failed: StandardError/)
304
304
  end
305
305
  end
306
306
  end
@@ -319,9 +319,9 @@ describe 'Retryable writes integration tests' do
319
319
  end
320
320
 
321
321
  it 'does not retry writes' do
322
- expect {
322
+ expect do
323
323
  operation
324
- }.to raise_error(Mongo::Error::SocketError)
324
+ end.to raise_error(Mongo::Error::SocketError)
325
325
  expect(expectation).to eq(unsuccessful_retry_value)
326
326
  end
327
327
  end
@@ -341,9 +341,9 @@ describe 'Retryable writes integration tests' do
341
341
  end
342
342
 
343
343
  it 'does not retry writes' do
344
- expect {
344
+ expect do
345
345
  operation
346
- }.to raise_error(Mongo::Error::SocketError)
346
+ end.to raise_error(Mongo::Error::SocketError)
347
347
  expect(expectation).to eq(unsuccessful_retry_value)
348
348
  end
349
349
  end