moped 2.0.3 → 2.0.7

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 4c42ef9279d08c76ecf69539b067b93ab0878f4e
4
- data.tar.gz: 3a12fc6c37618f64b7554483f186bac840df90bb
3
+ metadata.gz: eda09d3428a61f892b3d983486b0bcacb4d22c1f
4
+ data.tar.gz: 0d496810ace691461b3443f1163102a76f85ec5b
5
5
  SHA512:
6
- metadata.gz: a636e60201e811f5ea5334ae6e2d3418e2c3c483ae992183172abadadf5ffa0b1682acbac4e03684e4d2dede020d3f562e3a512dbfe6395b19615746fc121707
7
- data.tar.gz: b733ee7605f748665b060621b7a65bc1ee2ca610f6079ca96c76563329b9140f25468c618e96986abda5be9e963aa52881c6f3982f98d99c5245ae415170c428
6
+ metadata.gz: 951ba327262a778af25d190b5f80332c10bac5f8186194c399091bb924bcab9c625f4b317d3807390a2fc233f3c2f2a7cfb1f499045363743ec2e6a789581043
7
+ data.tar.gz: 8a5fcdd582261c79a7d1fd241d17ffd437bd4232e3a663e040c316fa8c2bc29e15c56399fa2e677e8971c1687cbbafd8743ba4fc6af6b1c97eb888ca1a4d6c56
data/CHANGELOG.md CHANGED
@@ -1,5 +1,29 @@
1
1
  # Overview
2
2
 
3
+ ## 2.0.7
4
+
5
+ * Improved Moped Failover (John Hyman)
6
+
7
+ ## 2.0.6
8
+
9
+ * Relaxing BSON dependency to allow for 3.1.0 upgrade.
10
+
11
+ ## 2.0.5
12
+
13
+ ### Resolved Issues
14
+
15
+ * \#351
16
+ Fixing retries with authentication. (Wandenberg Peixoto)
17
+
18
+ * Bump BSON dependency to 3.0.4
19
+
20
+ ## 2.0.4
21
+
22
+ ### Resolved Issues
23
+
24
+ * \#345
25
+ Writes fail with ConnectionPool::PoolShuttingDownError. (fedenusy, dblock)
26
+
3
27
  ## 2.0.3
4
28
 
5
29
  ### Resolved Issues
data/lib/moped/address.rb CHANGED
@@ -45,9 +45,13 @@ module Moped
45
45
  #
46
46
  # @since 2.0.0
47
47
  def resolve(node)
48
+ return @resolved if @resolved
49
+ start = Time.now
50
+ retries = 0
48
51
  begin
49
- return @resolved if @resolved
50
- Timeout::timeout(@timeout) do
52
+ # This timeout should be very large since Timeout::timeout plays very badly with multithreaded code
53
+ # TODO: Remove this Timeout entirely
54
+ Timeout::timeout(@timeout * 10) do
51
55
  Resolv.each_address(host) do |ip|
52
56
  if ip =~ Resolv::IPv4::Regex
53
57
  @ip ||= ip
@@ -57,9 +61,19 @@ module Moped
57
61
  raise Resolv::ResolvError unless @ip
58
62
  end
59
63
  @resolved = "#{ip}:#{port}"
60
- rescue Timeout::Error, Resolv::ResolvError, SocketError
61
- Loggable.warn(" MOPED:", "Could not resolve IP for: #{original}", "n/a")
62
- node.down! and false
64
+ rescue Timeout::Error, Resolv::ResolvError, SocketError => e
65
+ msg = [" MOPED:", "Could not resolve IP for: #{original}, delta is #{Time.now - start}, error class is #{e.inspect}, retries is #{retries}. Node is #{node.inspect}", "n/a"]
66
+ if retries == 0
67
+ Loggable.info(*msg)
68
+ else
69
+ Loggable.warn(*msg)
70
+ end
71
+ if retries < 2
72
+ retries += 1
73
+ retry
74
+ else
75
+ node.down! and false
76
+ end
63
77
  end
64
78
  end
65
79
  end
@@ -1,5 +1,6 @@
1
1
  # encoding: utf-8
2
2
  require "moped/query"
3
+ require "moped/retryable"
3
4
 
4
5
  module Moped
5
6
 
@@ -8,6 +9,7 @@ module Moped
8
9
  # @since 1.0.0
9
10
  class Collection
10
11
  include Readable
12
+ include Retryable
11
13
 
12
14
  # @!attribute database
13
15
  # @return [ Database ] The database for the collection.
@@ -120,9 +122,11 @@ module Moped
120
122
  #
121
123
  # @since 1.0.0
122
124
  def insert(documents, flags = nil)
123
- docs = documents.is_a?(Array) ? documents : [ documents ]
124
- cluster.with_primary do |node|
125
- node.insert(database.name, name, docs, write_concern, flags: flags || [])
125
+ with_retry(cluster) do
126
+ docs = documents.is_a?(Array) ? documents : [ documents ]
127
+ cluster.with_primary do |node|
128
+ node.insert(database.name, name, docs, write_concern, flags: flags || [])
129
+ end
126
130
  end
127
131
  end
128
132
 
@@ -48,10 +48,17 @@ module Moped
48
48
  #
49
49
  # @since 2.0.3
50
50
  def shutdown(node)
51
+ pool = nil
51
52
  MUTEX.synchronize do
52
53
  pool = pools.delete(node.address.resolved)
53
- pool.shutdown{ |conn| conn.disconnect } if pool
54
- nil
54
+ end
55
+ pool.shutdown{ |conn| conn.disconnect } if pool
56
+ nil
57
+ end
58
+
59
+ def delete_pool(node)
60
+ MUTEX.synchronize do
61
+ pools.delete(node.address.resolved)
55
62
  end
56
63
  end
57
64
 
@@ -3,7 +3,6 @@ require "moped/connection/manager"
3
3
  require "moped/connection/sockets"
4
4
 
5
5
  module Moped
6
-
7
6
  # This class contains behaviour of database socket connections.
8
7
  #
9
8
  # @since 2.0.0
@@ -15,6 +14,8 @@ module Moped
15
14
  # @since 2.0.0
16
15
  TIMEOUT = 5
17
16
 
17
+ REPLY_DECODE_STR = 'l<5q<l<2'
18
+
18
19
  # @!attribute host
19
20
  # @return [ String ] The ip address of the host.
20
21
  # @!attribute options
@@ -114,15 +115,15 @@ module Moped
114
115
  with_connection do |socket|
115
116
  reply = Protocol::Reply.allocate
116
117
  data = read_data(socket, 36)
117
- response = data.unpack('l<5q<l<2')
118
+ response = data.unpack(REPLY_DECODE_STR)
118
119
  reply.length,
119
- reply.request_id,
120
- reply.response_to,
121
- reply.op_code,
122
- reply.flags,
123
- reply.cursor_id,
124
- reply.offset,
125
- reply.count = response
120
+ reply.request_id,
121
+ reply.response_to,
122
+ reply.op_code,
123
+ reply.flags,
124
+ reply.cursor_id,
125
+ reply.offset,
126
+ reply.count = response
126
127
 
127
128
  if reply.count == 0
128
129
  reply.documents = []
data/lib/moped/cursor.rb CHANGED
@@ -6,6 +6,7 @@ module Moped
6
6
  class Cursor
7
7
  include Readable
8
8
  include Enumerable
9
+ include Retryable
9
10
 
10
11
  # @attribute [r] get_more_op The get more message.
11
12
  # @attribute [r] kill_cursor_op The kill cursor message.
@@ -43,10 +44,12 @@ module Moped
43
44
  #
44
45
  # @since 1.0.0
45
46
  def get_more
46
- reply = @node.get_more @database, @collection, @cursor_id, request_limit
47
- @limit -= reply.count if limited?
48
- @cursor_id = reply.cursor_id
49
- reply.documents
47
+ with_retry(session.cluster) do
48
+ reply = @node.get_more @database, @collection, @cursor_id, request_limit
49
+ @limit -= reply.count if limited?
50
+ @cursor_id = reply.cursor_id
51
+ reply.documents
52
+ end
50
53
  end
51
54
 
52
55
  # Determine the request limit for the query
data/lib/moped/errors.rb CHANGED
@@ -112,10 +112,10 @@ module Moped
112
112
  class PotentialReconfiguration < MongoError
113
113
 
114
114
  # Not master error codes.
115
- NOT_MASTER = [ 13435, 13436, 10009 ]
115
+ NOT_MASTER = [ 13435, 13436, 10009, 15986, 83 ]
116
116
 
117
117
  # Error codes received around reconfiguration
118
- CONNECTION_ERRORS_RECONFIGURATION = [ 15988, 10276, 11600, 9001, 13639, 10009, 11002 ]
118
+ CONNECTION_ERRORS_RECONFIGURATION = [ 15988, 10276, 11600, 9001, 13639, 10009, 11002, 7 ]
119
119
 
120
120
  # Replica set reconfigurations can be either in the form of an operation
121
121
  # error with code 13435, or with an error message stating the server is
@@ -126,7 +126,8 @@ module Moped
126
126
  end
127
127
 
128
128
  def connection_failure?
129
- CONNECTION_ERRORS_RECONFIGURATION.include?(details["code"])
129
+ err = details["err"] || details["errmsg"] || details["$err"] || ""
130
+ CONNECTION_ERRORS_RECONFIGURATION.include?(details["code"]) || err.include?("could not get last error") || err.include?("connection attempt failed")
130
131
  end
131
132
 
132
133
  # Is the error due to a namespace not being found?
@@ -9,7 +9,7 @@ module Moped
9
9
  module Retry
10
10
  extend self
11
11
 
12
- # Executes the failover strategy. In the case of retyr, we disconnect and
12
+ # Executes the failover strategy. In the case of retry, we disconnect and
13
13
  # reconnect, then try the operation one more time.
14
14
  #
15
15
  # @example Execute the retry strategy.
@@ -24,11 +24,13 @@ module Moped
24
24
  #
25
25
  # @since 2.0.0
26
26
  def execute(exception, node)
27
- node.disconnect
27
+ node.disconnect unless exception.is_a?(Errors::PoolTimeout)
28
28
  begin
29
29
  node.connection do |conn|
30
30
  yield(conn) if block_given?
31
31
  end
32
+ rescue Errors::PoolTimeout => e
33
+ raise Errors::ConnectionFailure.new e
32
34
  rescue Exception => e
33
35
  node.down!
34
36
  raise(e)
@@ -21,7 +21,8 @@ module Moped
21
21
  Errors::ConnectionFailure => Retry,
22
22
  Errors::CursorNotFound => Ignore,
23
23
  Errors::OperationFailure => Reconfigure,
24
- Errors::QueryFailure => Reconfigure
24
+ Errors::QueryFailure => Reconfigure,
25
+ Errors::PoolTimeout => Retry
25
26
  }.freeze
26
27
 
27
28
  # Get the appropriate failover handler given the provided exception.
@@ -42,6 +42,10 @@ module Moped
42
42
  Moped.logger.debug([ prefix, payload, "runtime: #{runtime}" ].join(' '))
43
43
  end
44
44
 
45
+ def self.info(prefix, payload, runtime)
46
+ Moped.logger.info([ prefix, payload, "runtime: #{runtime}" ].join(' '))
47
+ end
48
+
45
49
  # Log the payload to warn.
46
50
  #
47
51
  # @example Log to warn.
data/lib/moped/node.rb CHANGED
@@ -111,8 +111,19 @@ module Moped
111
111
  #
112
112
  # @since 2.0.0
113
113
  def connection
114
- pool.with do |conn|
115
- yield(conn)
114
+ connection_acquired = false
115
+ begin
116
+ pool.with do |conn|
117
+ connection_acquired = true
118
+ yield(conn)
119
+ end
120
+ rescue Timeout::Error, ConnectionPool::PoolShuttingDownError => e
121
+ if e.kind_of?(ConnectionPool::PoolShuttingDownError)
122
+ @pool = nil
123
+ Connection::Manager.delete_pool(self)
124
+ raise Errors::PoolTimeout.new(e)
125
+ end
126
+ raise connection_acquired ? e : Errors::PoolTimeout.new(e)
116
127
  end
117
128
  end
118
129
 
@@ -150,10 +161,10 @@ module Moped
150
161
  #
151
162
  # @since 2.0.0
152
163
  def down!
153
- @pool = Connection::Manager.shutdown(self)
154
164
  @down_at = Time.new
165
+ @pool = nil
155
166
  @latency = nil
156
- true
167
+ Connection::Manager.shutdown(self)
157
168
  end
158
169
 
159
170
  # Yields the block if a connection can be established, retrying when a
@@ -182,6 +193,10 @@ module Moped
182
193
  yield(conn)
183
194
  end
184
195
  rescue Exception => e
196
+ if e.kind_of?(ConnectionPool::PoolShuttingDownError)
197
+ @pool = nil
198
+ Connection::Manager.delete_pool(self)
199
+ end
185
200
  Failover.get(e).execute(e, self, &block)
186
201
  ensure
187
202
  end_execution(:connection)
@@ -198,7 +213,7 @@ module Moped
198
213
  #
199
214
  # @return [ nil ] nil.
200
215
  #
201
- # @since 1.0.0
216
+ # @since 1.0.0s
202
217
  def ensure_primary
203
218
  execute(:ensure_primary) do
204
219
  yield(self)
@@ -585,14 +600,14 @@ module Moped
585
600
  def flush(ops = queue)
586
601
  operations, callbacks = ops.transpose
587
602
  logging(operations) do
588
- replies = nil
589
603
  ensure_connected do |conn|
590
604
  conn.write(operations)
591
605
  replies = conn.receive_replies(operations)
606
+
607
+ replies.zip(callbacks).map do |reply, callback|
608
+ callback ? callback[reply] : reply
609
+ end.last
592
610
  end
593
- replies.zip(callbacks).map do |reply, callback|
594
- callback ? callback[reply] : reply
595
- end.last
596
611
  end
597
612
  ensure
598
613
  ops.clear
@@ -46,10 +46,27 @@ module Moped
46
46
  # @since 2.0.0
47
47
  def execute(node)
48
48
  node.process(operation) do |reply|
49
- if operation.failure?(reply)
50
- raise operation.failure_exception(reply)
49
+ # Avoid LocalJumpError
50
+ ret = nil
51
+ if reply.unauthorized? && node.credentials.key?(@database)
52
+ node.connection do |conn|
53
+ username, password = node.credentials[@database]
54
+ if username && password
55
+ conn.login(operation.database, username, password)
56
+ ret = execute(node)
57
+ end
58
+ end
51
59
  end
52
- operation.results(reply)
60
+
61
+ if ret.nil?
62
+ if operation.failure?(reply)
63
+ raise operation.failure_exception(reply)
64
+ end
65
+
66
+ ret = operation.results(reply)
67
+ end
68
+
69
+ ret
53
70
  end
54
71
  end
55
72
  end
@@ -1,6 +1,5 @@
1
1
  module Moped
2
2
  module Protocol
3
-
4
3
  # The base class for building all messages needed to implement the Mongo
5
4
  # Wire Protocol. It provides a minimal DSL for defining typed fields for
6
5
  # serialization and deserialization over the wire.
@@ -34,6 +33,9 @@ module Moped
34
33
  # int32 :op_code
35
34
  #
36
35
  module Message
36
+ INT32_DECODE_STR = 'l<'
37
+ INT64_DECODE_ARRAY_STR = 'q<*'
38
+ INT64_DECODE_STR = 'q<'
37
39
 
38
40
  # Default implementation for a message is to do nothing when receiving
39
41
  # replies.
@@ -214,11 +216,11 @@ module Moped
214
216
  end
215
217
 
216
218
  def serialize_#{name}(buffer)
217
- buffer << [#{name}_as_int].pack('l<')
219
+ buffer << [#{name}_as_int].pack(INT32_DECODE_STR)
218
220
  end
219
221
 
220
222
  def deserialize_#{name}(buffer)
221
- bits, = buffer.read(4).unpack('l<')
223
+ bits, = buffer.read(4).unpack(INT32_DECODE_STR)
222
224
 
223
225
  self.#{name} = bits
224
226
  end
@@ -244,11 +246,11 @@ module Moped
244
246
  end
245
247
 
246
248
  def serialize_#{name}(buffer)
247
- buffer << [#{name}].pack('l<')
249
+ buffer << [#{name}].pack(INT32_DECODE_STR)
248
250
  end
249
251
 
250
252
  def deserialize_#{name}(buffer)
251
- self.#{name}, = buffer.read(4).unpack('l<')
253
+ self.#{name}, = buffer.read(4).unpack(INT32_DECODE_STR)
252
254
  end
253
255
  RUBY
254
256
 
@@ -280,7 +282,7 @@ module Moped
280
282
  end
281
283
 
282
284
  def serialize_#{name}(buffer)
283
- buffer << #{name}.pack('q<*')
285
+ buffer << #{name}.pack(INT64_DECODE_ARRAY_STR)
284
286
  end
285
287
 
286
288
  def deserialize_#{name}(buffer)
@@ -294,11 +296,11 @@ module Moped
294
296
  end
295
297
 
296
298
  def serialize_#{name}(buffer)
297
- buffer << [#{name}].pack('q<')
299
+ buffer << [#{name}].pack(INT64_DECODE_STR)
298
300
  end
299
301
 
300
302
  def deserialize_#{name}(buffer)
301
- self.#{name}, = buffer.read(8).unpack('q<')
303
+ self.#{name}, = buffer.read(8).unpack(INT64_DECODE_STR)
302
304
  end
303
305
  RUBY
304
306
  end
data/lib/moped/query.rb CHANGED
@@ -21,6 +21,7 @@ module Moped
21
21
  # people.find.count # => 1
22
22
  class Query
23
23
  include Enumerable
24
+ include Retryable
24
25
 
25
26
  # @attribute [r] collection The collection to execute the query on.
26
27
  # @attribute [r] operation The query operation.
@@ -321,14 +322,16 @@ module Moped
321
322
  #
322
323
  # @since 1.0.0
323
324
  def remove
324
- cluster.with_primary do |node|
325
- node.remove(
326
- operation.database,
327
- operation.collection,
328
- operation.basic_selector,
329
- write_concern,
330
- flags: [ :remove_first ]
331
- )
325
+ with_retry(cluster) do
326
+ cluster.with_primary do |node|
327
+ node.remove(
328
+ operation.database,
329
+ operation.collection,
330
+ operation.basic_selector,
331
+ write_concern,
332
+ flags: [ :remove_first ]
333
+ )
334
+ end
332
335
  end
333
336
  end
334
337
 
@@ -341,13 +344,15 @@ module Moped
341
344
  #
342
345
  # @since 1.0.0
343
346
  def remove_all
344
- cluster.with_primary do |node|
345
- node.remove(
346
- operation.database,
347
- operation.collection,
348
- operation.basic_selector,
349
- write_concern
350
- )
347
+ with_retry(cluster) do
348
+ cluster.with_primary do |node|
349
+ node.remove(
350
+ operation.database,
351
+ operation.collection,
352
+ operation.basic_selector,
353
+ write_concern
354
+ )
355
+ end
351
356
  end
352
357
  end
353
358
 
@@ -423,15 +428,17 @@ module Moped
423
428
  #
424
429
  # @since 1.0.0
425
430
  def update(change, flags = nil)
426
- cluster.with_primary do |node|
427
- node.update(
428
- operation.database,
429
- operation.collection,
430
- operation.selector["$query"] || operation.selector,
431
- change,
432
- write_concern,
433
- flags: flags
434
- )
431
+ with_retry(cluster) do
432
+ cluster.with_primary do |node|
433
+ node.update(
434
+ operation.database,
435
+ operation.collection,
436
+ operation.selector["$query"] || operation.selector,
437
+ change,
438
+ write_concern,
439
+ flags: flags
440
+ )
441
+ end
435
442
  end
436
443
  end
437
444
 
@@ -1,4 +1,5 @@
1
1
  # encoding: utf-8
2
+ require "moped/retryable"
2
3
  module Moped
3
4
  module ReadPreference
4
5
 
@@ -7,6 +8,7 @@ module Moped
7
8
  #
8
9
  # @since 2.0.0
9
10
  module Selectable
11
+ include Retryable
10
12
 
11
13
  # @!attribute tags
12
14
  # @return [ Array<Hash> ] The tag sets.
@@ -39,41 +41,6 @@ module Moped
39
41
  options[:flags] |= [ :slave_ok ]
40
42
  options
41
43
  end
42
-
43
- private
44
-
45
- # Execute the provided block on the cluster and retry if the execution
46
- # fails.
47
- #
48
- # @api private
49
- #
50
- # @example Execute with retry.
51
- # preference.with_retry(cluster) do
52
- # cluster.with_primary do |node|
53
- # node.refresh
54
- # end
55
- # end
56
- #
57
- # @param [ Cluster ] cluster The cluster.
58
- # @param [ Integer ] retries The number of times to retry.
59
- #
60
- # @return [ Object ] The result of the block.
61
- #
62
- # @since 2.0.0
63
- def with_retry(cluster, retries = cluster.max_retries, &block)
64
- begin
65
- block.call
66
- rescue Errors::ConnectionFailure => e
67
- if retries > 0
68
- Loggable.warn(" MOPED:", "Retrying connection attempt #{retries} more time(s).", "n/a")
69
- sleep(cluster.retry_interval)
70
- cluster.refresh
71
- with_retry(cluster, retries - 1, &block)
72
- else
73
- raise e
74
- end
75
- end
76
- end
77
44
  end
78
45
  end
79
46
  end
@@ -0,0 +1,46 @@
1
+ # encoding: utf-8
2
+ module Moped
3
+ # Provides the shared behaviour for retry failed operations.
4
+ #
5
+ # @since 2.0.0
6
+ module Retryable
7
+
8
+ private
9
+
10
+ # Execute the provided block on the cluster and retry if the execution
11
+ # fails.
12
+ #
13
+ # @api private
14
+ #
15
+ # @example Execute with retry.
16
+ # preference.with_retry(cluster) do
17
+ # cluster.with_primary do |node|
18
+ # node.refresh
19
+ # end
20
+ # end
21
+ #
22
+ # @param [ Cluster ] cluster The cluster.
23
+ # @param [ Integer ] retries The number of times to retry.
24
+ #
25
+ # @return [ Object ] The result of the block.
26
+ #
27
+ # @since 2.0.0
28
+ def with_retry(cluster, retries = cluster.max_retries, &block)
29
+ begin
30
+ block.call
31
+ rescue Errors::ConnectionFailure, Errors::PotentialReconfiguration => e
32
+ raise e if e.is_a?(Errors::PotentialReconfiguration) &&
33
+ ! (e.message.include?("not master") || e.message.include?("Not primary"))
34
+
35
+ if retries > 0
36
+ Loggable.warn(" MOPED:", "Retrying connection attempt #{retries} more time(s), nodes is #{cluster.nodes.inspect}, seeds are #{cluster.seeds.inspect}, cluster is #{cluster.inspect}. Error backtrace is #{e.backtrace}.", "n/a")
37
+ sleep(cluster.retry_interval)
38
+ cluster.refresh
39
+ with_retry(cluster, retries - 1, &block)
40
+ else
41
+ raise e
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
data/lib/moped/version.rb CHANGED
@@ -1,4 +1,4 @@
1
1
  # encoding: utf-8
2
2
  module Moped
3
- VERSION = "2.0.3"
3
+ VERSION = "2.0.7"
4
4
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: moped
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.3
4
+ version: 2.0.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Durran Jordan
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2015-01-02 00:00:00.000000000 Z
12
+ date: 2015-08-15 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bson
@@ -17,14 +17,14 @@ dependencies:
17
17
  requirements:
18
18
  - - "~>"
19
19
  - !ruby/object:Gem::Version
20
- version: '2.2'
20
+ version: '3.0'
21
21
  type: :runtime
22
22
  prerelease: false
23
23
  version_requirements: !ruby/object:Gem::Requirement
24
24
  requirements:
25
25
  - - "~>"
26
26
  - !ruby/object:Gem::Version
27
- version: '2.2'
27
+ version: '3.0'
28
28
  - !ruby/object:Gem::Dependency
29
29
  name: connection_pool
30
30
  requirement: !ruby/object:Gem::Requirement
@@ -114,6 +114,7 @@ files:
114
114
  - lib/moped/read_preference/secondary_preferred.rb
115
115
  - lib/moped/read_preference/selectable.rb
116
116
  - lib/moped/readable.rb
117
+ - lib/moped/retryable.rb
117
118
  - lib/moped/session.rb
118
119
  - lib/moped/uri.rb
119
120
  - lib/moped/version.rb