moped 2.0.3 → 2.0.7

Sign up to get free protection for your applications and to get access to all the features.
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