Retryable Writes in MongoDB

MongoDB 3.4 offered some great new features. MongoDB version 3.6 is quickly approaching a final release date and is introducing many new features too. As I discussed previously, one feature is change streams. Another very exciting and much anticipated new feature is retryable writes.

The Need for Retryable Writes

In previous versions of MongoDB, it was incumbent upon the developer and the application to handle situations where a write doesn’t happen. Imagine sending a create or update command to your database and something happens. A network partition occurs, a primary steps down, or a butterfly flaps it’s wings in Ecuador and causes a network malfunction in Chicago. Or any other host of possibilities.

Driver Handling

Retryable writes in version 3.6 removes the handling of these system failures from the application to the database itself. The MongoDB driver is now capable of automatically retrying many write operations. Meanwhile, the server is in charge of the handling the processing of the write request and the exactly-once concept.

Supported Retryable Write Operations

MongoDB 3.6 supports this functionality for single-statement write operations such as:

  • insertOne()
  • updateOne()
  • replaceOne()
  • deleteOne()
  • findOneAndDelete()
  • findOneAndReplace()
  • findOneAndUpdate()

Supported multi-statement operations include insertMany() and bulkWrite(). Although there are some limitations to using bulkWrite() with the new feature.

Retryable Write Limitations

In MongoDB 3.6 there are a few current limitations where retryable behavior isn’t supported. Although these limitations may be removed in the future.

  1. Writes with an unacknowledged write concern, {w: 0}
  2. Write commands that might affect multiple documents using a single statement
  3. Commands other than insert, delete, update, and findAndModify. For example, aggregation commands using the $out operator.

How it Works in a Nutshell

As I mentioned, retryable writes are handled on the server. But it is implemented through the driver through another new feature in MongoDB 3.6, logical sessions. By creating a session with the server, we are now able to establish a unique transaction identifier for each write operation.

> var session = startSession( { retry_writes : True });
> session.db.collection.updateOne({'_id': 1}, 
     {'$inc': {'counter': 5}}

Or in a Python example:

uri = "mongodb://"
client = MongoClient(uri)
database = client.database
collection = database.collection

This transaction identifier for the session is re-sent to the server, by the driver, to determine the success of a previous write attempt. This implementation brings with it some big wins.

  • No extra code is needed for applications, such as save points or retry logic.
  • Retryable writes aren’t limited only to idempotent operations.
  • They are safe for operations that fail acknowledge write success due to timeout exceptions.

Wrap Up

Retryable writes are yet another great feature brought forth by the team at MongoDB. For applications that simply cannot tolerate any loss of write operations, retryable writes are a big benefit. One of the many reasons to look at the latest release of MongoDB.

Follow me on Twitter @kenwalger to get the latest updates on my postings.

There are a few MongoDB specific terms in this post. I created a MongoDB Dictionary skill for the Amazon Echo line of products. Check it out and you can say “Alexa, ask MongoDB for the definition of a document?” and get a helpful response.