Version 4.0 of the MongoDB server introduces multi-document transactions. (Updates to multiple fields within a single document are atomic in all versions of MongoDB.) Ruby driver version 2.6.0 adds support for transactions.

Using Transactions

In order to start a transaction, the application must have a session.

The recommended way to use transactions is to utilize the with_transaction helper method:

session = client.start_session
session.with_transaction do
  collection.insert_one(hello: 'world')

The with_transaction helper does the following:

  • It starts a transaction prior to calling the supplied block, and commits

the transaction when the block finishes. - If any of the operations in the block, or the commit operation, result in a transient transaction error, the block and/or the commit will be executed again.

The block should be idempotent, because it may be called multiple times.

The block may explicitly commit or abort the transaction, by calling commit_transaction or abort_transaction; in this case with_transaction will not attempt to commit or abort (but may still retry the block on transient transaction errors propagated out of the block).

The block will also be retried if the transaction’s commit result is unknown. This may happen, for example, if the cluster undergoes an election during the commit. In this case when the block is retried, the primary server of the topology would likely have changed.

Currently with_transaction will stop retrying the block and the commit once 120 seconds pass since the beginning of its execution. This time is not configurable and may change in a future driver version. Note that this does not guarantee the overall runtime of with_transactions will be 120 seconds or less - just that once 120 seconds of wall clock time have elapsed, further retry attempts will not be initiated.

A low level API is also available if more control over transactions is desired.

with_transaction takes the same options as start_transaction does, which are read concern, write concern and read preference:

session = client.start_session
  read_concern: {level: :majority},
  write_concern: {w: 3},
  read: {mode: :primary}
) do
  collection.insert_one(hello: 'world')

Low Level API

A transaction can be started by calling the start_transaction method on a session:

session = client.start_session

It is also possible to specify read concern, write concern and read preference when starting a transaction:

session = client.start_session
  read_concern: {level: :majority},
  write_concern: {w: 3},
  read: {mode: :primary})

To persist changes made in a transaction to the database, the transaction must be explicitly committed. If a session ends with an open transaction, the transaction is aborted. A transaction may also be aborted explicitly.

To commit or abort a transaction, call commit_transaction or abort_transaction on the session instance:



Retrying Commits

The transaction commit can be retried if it fails. Here is the Ruby code to do so:

rescue Mongo::Error => e

Transaction Nesting

MongoDB does not support nesting transactions. Attempting to call start_transaction or with_transaction when a transaction is already in progress will result in an error.

←   Sessions Change Streams  →