Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 78 additions & 0 deletions Examples/Docs/Sources/AsyncExamples/main.swift
Original file line number Diff line number Diff line change
Expand Up @@ -147,3 +147,81 @@ private func changeStreams() throws {
// End Changestream Example 4
}
}

/// Examples used for the MongoDB documentation on transactions.
/// - SeeAlso: https://docs.mongodb.com/manual/core/transactions-in-applications/
private func transactions() throws {
let elg = MultiThreadedEventLoopGroup(numberOfThreads: 1)
let client = try MongoClient(using: elg)

// Start Transactions Into Example 1
func updateEmployeeInfo(session: ClientSession) -> EventLoopFuture<Void> {
let employees = client.db("hr").collection("employees")
let events = client.db("reporting").collection("events")

let options = TransactionOptions(readConcern: .snapshot, writeConcern: .majority)
return session.startTransaction(options: options).flatMap {
employees.updateOne(
filter: ["employee": 3],
update: ["$set": ["status": "Inactive"]],
session: session
).flatMap { _ in
events.insertOne(["employee": 3, "status": ["new": "Inactive", "old": "Active"]])
}.flatMapError { error in
print("Caught error during transaction, aborting")
return session.abortTransaction().flatMapThrowing { _ in
throw error
}
}
}.flatMap { _ in
commitWithRetry(session: session)
}
}
// End Transactions Intro Example 1

// Start Transactions Retry Example 1
func runTransactionWithRetry(
session: ClientSession,
txnFunc: @escaping (ClientSession) -> EventLoopFuture<Void>
) -> EventLoopFuture<Void> {
let txnFuture = txnFunc(session)
let eventLoop = txnFuture.eventLoop
return txnFuture.flatMapError { error in
guard
let labeledError = error as? LabeledError,
labeledError.errorLabels?.contains("TransientTransactionError") == true
else {
return eventLoop.makeFailedFuture(error)
}
print("TransientTransactionError, retrying transaction...")
return runTransactionWithRetry(session: session, txnFunc: txnFunc)
}
}
// End Transactions Retry Example 1

// Start Transactions Retry Example 2
func commitWithRetry(session: ClientSession) -> EventLoopFuture<Void> {
let commitFuture = session.commitTransaction()
let eventLoop = commitFuture.eventLoop
return commitFuture.flatMapError { error in
guard
let labeledError = error as? LabeledError,
labeledError.errorLabels?.contains("UnknownTransactionCommitResult") == true
else {
print("Error during commit...")
return eventLoop.makeFailedFuture(error)
}
print("UnknownTransactionCommitResult, retrying commit operation...")
return commitWithRetry(session: session)
}
}
// End Transactions Retry Example 2

// Start Transactions Retry Example 3
try client.withSession { session in
runTransactionWithRetry(session: session, txnFunc: updateEmployeeInfo).flatMapErrorThrowing { _ in
// do something with error
}
}.wait()
// End Transactions Retry Example 3
}
75 changes: 75 additions & 0 deletions Examples/Docs/Sources/SyncExamples/main.swift
Original file line number Diff line number Diff line change
Expand Up @@ -90,3 +90,78 @@ private func changeStreams() throws {
// End Changestream Example 4
}
}

/// Examples used for the MongoDB documentation on transactions.
/// - SeeAlso: https://docs.mongodb.com/manual/core/transactions-in-applications/
private func transactions() throws {
// Start Transactions Intro Example 1
func updateEmployeeInfo(session: ClientSession) throws {
let employees = session.client.db("hr").collection("employees")
let events = session.client.db("reporting").collection("events")

do {
try employees.updateOne(filter: ["employee": 3], update: ["$set": ["status": "Inactive"]], session: session)
try events.insertOne(["employee": 3, "status": ["new": "Inactive", "old": "Active"]], session: session)
} catch {
print("Caught error during transaction, aborting")
try session.abortTransaction()
throw error
}
try commitWithRetry(session: session)
}
// End Transactions Intro Example 1

// Start Transactions Retry Example 1
func runTransactionWithRetry(session: ClientSession, txnFunc: @escaping (ClientSession) throws -> Void) throws {
while true {
do {
return try txnFunc(session) // performs transaction
} catch {
print("Transaction aborted. Caught exception during transaction.")
guard
let labeledError = error as? LabeledError,
labeledError.errorLabels?.contains("TransientTransactionError") == true
else {
throw error
}
// If transient error, retry the whole transaction
print("TransientTransactionError, retrying transaction ...")
continue
}
}
}
// End Transactions Retry Example 1

// Start Transactions Retry Example 2
func commitWithRetry(session: ClientSession) throws {
while true {
do {
try session.commitTransaction() // Uses write concern set at transaction start
print("Transaction committed.")
break
} catch {
guard
let labeledError = error as? LabeledError,
labeledError.errorLabels?.contains("UnknownTransactionCommitResult") == true
else {
print("Error during commit ...")
throw error
}
print("UnknownTransactionCommitResult, retrying commit operation ...")
continue
}
}
}
// End Transactions Retry Example 2

let client = try MongoClient()
// Start Transactions Retry Example 3
client.withSession { session in
do {
try runTransactionWithRetry(session: session, txnFunc: updateEmployeeInfo)
} catch {
// do something with error
}
}
// End Transactions Retry Example 3
}