Module: Mongo::Retryable

Overview

Defines basic behavior around retrying operations.

Since:

  • 2.1.0

Instance Method Summary collapse

Instance Method Details

#read_with_one_retry(options = nil) ⇒ Result

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Note:

This only retries read operations on socket errors.

Execute a read operation with a single retry.

Examples:

Execute the read.

read_with_one_retry do
  ...
end

Parameters:

  • options (Hash) (defaults to: nil)

    Options.

  • block (Proc)

    The block to execute.

Options Hash (options):

  • :retry_message (String)

    Message to log when retrying.

Returns:

  • (Result)

    The result of the operation.

Since:

  • 2.2.6



84
85
86
87
88
89
90
# File 'lib/mongo/retryable.rb', line 84

def read_with_one_retry(options = nil)
  yield
rescue Error::SocketError, Error::SocketTimeoutError => e
  retry_message = options && options[:retry_message]
  log_retry(e, message: retry_message)
  yield
end

#read_with_retry(session = nil) ⇒ Result

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Note:

This only retries read operations on socket errors.

Execute a read operation with a retry.

Examples:

Execute the read.

read_with_retry do
  ...
end

Parameters:

  • session (Mongo::Session) (defaults to: nil)

    The session that the operation is being run on.

  • block (Proc)

    The block to execute.

Returns:

  • (Result)

    The result of the operation.

Since:

  • 2.1.0



39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
# File 'lib/mongo/retryable.rb', line 39

def read_with_retry(session = nil)
  attempt = 0
  begin
    attempt += 1
    yield
  rescue Error::SocketError, Error::SocketTimeoutError => e
    if attempt > cluster.max_read_retries || (session && session.in_transaction?)
      raise
    end
    log_retry(e)
    cluster.scan!(false)
    retry
  rescue Error::OperationFailure => e
    if cluster.sharded? && e.retryable? && !(session && session.in_transaction?)
      if attempt > cluster.max_read_retries
        raise
      end
      log_retry(e)
      sleep(cluster.read_retry_interval)
      retry
    else
      raise
    end
  end
end

#write_with_retry(session, write_concern, ending_transaction = false, &block) {|server, txn_num| ... } ⇒ Result

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Note:

This only retries operations on not master failures, since it is the only case we can be sure a partial write did not already occur.

Implements write retrying functionality by yielding to the passed block one or more times.

If the session is provided (hence, the deployment supports sessions), and modern retry writes are enabled on the client, the modern retry logic is invoked. Otherwise the legacy retry logic is invoked.

If ending_transaction parameter is true, indicating that a transaction is being committed or aborted, the operation is executed exactly once. Note that, since transactions require sessions, this method will raise ArgumentError if ending_transaction is true and session is nil.

Examples:

Execute the write.

write_with_retry do
  ...
end

Parameters:

  • session (nil | Session)

    Optional session to use with the operation.

  • write_concern (nil | Hash | WriteConcern::Base)

    The write concern.

  • ending_transaction (true | false) (defaults to: false)

    True if the write operation is abortTransaction or commitTransaction, false otherwise.

  • block (Proc)

    The block to execute.

Yield Parameters:

  • server (Server)

    The server to which the write should be sent.

  • txn_num (Integer)

    Transaction number (NOT the ACID kind).

Returns:

  • (Result)

    The result of the operation.

Since:

  • 2.1.0



126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
# File 'lib/mongo/retryable.rb', line 126

def write_with_retry(session, write_concern, ending_transaction = false, &block)
  if ending_transaction && !session
    raise ArgumentError, 'Cannot end a transaction without a session'
  end

  unless ending_transaction || retry_write_allowed?(session, write_concern)
    return legacy_write_with_retry(nil, session, &block)
  end

  # If we are here, session is not nil. A session being nil would have
  # failed retry_write_allowed? check.

  server = cluster.next_primary

  unless ending_transaction || server.retry_writes?
    return legacy_write_with_retry(server, session, &block)
  end

  begin
    txn_num = session.in_transaction? ? session.txn_num : session.next_txn_num
    yield(server, txn_num, false)
  rescue Error::SocketError, Error::SocketTimeoutError => e
    if session.in_transaction? && !ending_transaction
      raise
    end
    retry_write(e, txn_num, &block)
  rescue Error::OperationFailure => e
    if (session.in_transaction? && !ending_transaction) || !e.write_retryable?
      raise
    end
    retry_write(e, txn_num, &block)
  end
end