How Retryable Writes Works In MongoDB?
When MongoDB drivers experience network failures or are unable to locate a healthy primary in the replica set or sharded cluster, they can automatically retry specific write operations one time thanks to retryable writes.
Prerequisites
Retryable writes must meet the following criteria:
Supported Deployment Topologies
Retryable writes do not support standalone instances and necessitate a replica set or sharded cluster.
Supported Storage Engine
Storage engines that provide document-level locking, such the WiredTiger or in-memory storage engines, are necessary for retryable writes.
3.6+ MongoDB Drivers
Updated MongoDB drivers are necessary for clients using MongoDB 3.6 or above.
MongoDB Version
All cluster nodes must have a MongoDB version of 3.6 or above, and all cluster nodes must have a featureCompatibilityVersion of 3.6 or higher. For further details on the featureCompatibilityVersion flag, see setFeatureCompatibilityVersion.
Write Acknowledgment
Retries are not allowed for write operations that have a Write Concern of 0.
Retryable Writes and Multi-Document Transactions
Retryable writing operations are the transaction commit and abort functions. Whether or not retryWrites is set to false, MongoDB drivers only attempt a single retry of an operation in the event that an error occurs during the commit or abort process.
Regardless of the value of retryWrites, the write operations inside the transaction cannot be separately retried.
See Transactions for additional details on transactions.
Enabling Retryable Writes
MongoDB Drivers
Retryable Writes are enabled by default in drivers that are compatible with MongoDB 4.2 and later. For older drivers, the retryWrites=true option is necessary. Applications that use drivers compatible with MongoDB 4.2 and higher can omit the retryWrites=true option.
Applications that use drivers compatible with MongoDB 4.2 and higher must add retryWrites=false in the connection string in order to disable retryable writings.
In mongosh, retryable writes are enabled by default. Use the command line option — retryWrites=false to turn off retryable writes:
mongosh --retryWrites=false
Retryable Write Operations
When a write worry is raised, such as “Write Concern cannot be {w: 0},” the subsequent write operations are retryable.
Notes: There is no way to independently retry the write operations inside the transactions.
Methods - Descriptions
db.collection.insertOne(), db.collection.insertMany()
Insert operations.
db.collection.updateOne(), db.collection.replaceOne()
Single-document update operations.
db.collection.deleteOne(), db.collection.remove()
Single document delete operations.
db.collection.findAndModify(), db.collection.findOneAndDelete(), db.collection.findOneAndReplace(), db.collection.findOneAndUpdate() findAndModify
operations. All findAndModify
operations are single document operations.
Note: Updates to Shard Key Values
As of MongoDB 4.2, single-document update/findAndModify operations can be performed as a retryable write or in a transaction to alter a document’s shard key value (unless the shard key field is the immutable _id field). See Modify a Document’s Shard Key Value for further information.
Note: When a duplicate key exception occurs, MongoDB 4.2 will retry a subset of single-document upserts (update with upsert: true and multi: false). For conditions, see Duplicate Key Errors on Upsert.Before MongoDB 4.2, when an upsert operation met a duplicate key error, MongoDB would not attempt the operation again.
Behavior
Persistent Network Errors
Retryable writes in MongoDB only attempt a single retry. Replica set elections and momentary network issues are assisted by this, but permanent network errors are not addressed.
Failover Period
Before retrying, the drivers wait serverSelectionTimeoutMS milliseconds to identify the new primary in the target replica set or sharded cluster shard if they are unable to locate a healthy primary there. In situations where the failover interval beyond serverSelectionTimeoutMS, retryable writes are not addressed.
Note: It is possible that the write operation will be retried and applied again when the client application responds (without restarting) if it is unresponsive for longer than the localLogicalSessionTimeoutMinutes following the issuance of the write operation.
Duplicate Key Errors on Upsert
Only if all of the following criteria are met will MongoDB 4.2 attempt to retry single-document upsert operations (i.e., upsert : true and multi : false) that fail because of a duplicate key error.
- The duplicate key problem was brought on by the target collection’s unique index.
- The requirement for an update match is either:
A single equality predicate
{ "fieldA" : "valueA" }
,
or
a logical AND of equality predicates
{ "fieldA" : "valueA", "fieldB" : "valueB" }
- The set of fields in the update query predicate corresponds to the set of fields in the unique index key pattern.
- None of the fields in the query predicate are changed by the update operation.
Examples of upsert actions on duplicate key errors that the server can or cannot retry are shown in the following table:
#Unique Index Key Pattern
{ _id : 1 }
#Update Operation
db.collName.updateOne(
{ _id : ObjectId("1aa1c1efb123f14aaa167aaa") },
{ $set : { fieldA : 25 } },
{ upsert : true }
)
#Retryable
Yes
#Unique Index Key Pattern
{ fieldA : 1 }
#Update Operation
db.collName.updateOne(
{ fieldA : { $in : [ 25 ] } },
{ $set : { fieldB : "someValue" } },
{ upsert : true }
)
#Retryable
Yes
#Unique Index Key Pattern
{
fieldA : 1,
fieldB : 1
}
#Update Operation
db.collName.updateOne(
{ fieldA : 25, fieldB : "someValue" },
{ $set : { fieldC : false } },
{ upsert : true }
)
#Retryable
Yes
#Unique Index Key Pattern
{ fieldA : 1 }
#Update Operation
db.collName.updateOne(
{ fieldA : { $lte : 25 } },
{ $set : { fieldC : true } },
{ upsert : true }
)
#Retryable
No
The query predicate on fieldA is not an equality
#Unique Index Key Pattern
{ fieldA : 1 }
#Update Operation
db.collName.updateOne(
{ fieldA : { $in : [ 25 ] } },
{ $set : { fieldA : 20 } },
{ upsert : true }
)
#Retryable
No
The update operation modifies fields specified in the query predicate.
#Unique Index Key Pattern
{ _id : 1 }
#Update Operation
db.collName.updateOne(
{ fieldA : { $in : [ 25 ] } },
{ $set : { fieldA : 20 } },
{ upsert : true }
)
#Retryable
No
The set of query predicate fields (fieldA) does not match the set of index key fields (_id).
#Unique Index Key Pattern
{ fieldA : 1 }
#Update Operation
db.collName.updateOne(
{ fieldA : 25, fieldC : true },
{ $set : { fieldD : false } },
{ upsert : true }
)
#Retryable
No
The set of query predicate fields (fieldA, fieldC) does not match the set of index key fields (fieldA).
Up until MongoDB 4.2, retryable writes in MongoDB were not compatible with retrying upserts that failed because of duplicate key problems.
Diagnostics
In the transactions section, the serverStatus command and its mongosh shell helper db.serverStatus() provide data on retryable writes.
Retryable Writes Against local
Database
Retryable writes are enabled by default in the official MongoDB 4.2-series drivers. Upgrading to 4.2-series drivers will result in write errors for applications that write to the local database unless retryable writes are specifically disabled.
You can set retryWrites=false in the MongoDB cluster’s connection string to prevent retryable writes.
Error Handling
Beginning with MongoDB 6.1, MongoDB sends an error with the NoWritesPerformed label if a retryable write fails on both its first and second attempts without a single write being completed.
The NoWritesPerformed label is used to distinguish between the outcomes of batch processes such as insertMany(). When doing an insertMany operation, one of the following results is possible:
Outcome — MongoDB Output
No documents are inserted. — Error returned with NoWritesPerformed
label.
Partial work done. (At least one document is inserted, but not all.) — Error returned without NoWritesPerformed
label.
All documents are inserted. — Success returned.
Applications can conclusively establish that no documents were inserted by using the NoWritesPerformed label. When handling retryable writes, this error reporting enables the programme to keep an accurate state of the database.
When a retryable write fails on both the first and second try, an error is returned in earlier versions of MongoDB. That being said, no distinction is made to suggest that no writing were done.