Skip to content

Commit eb67196

Browse files
authored
SWIFT-423 Add transactions examples for docs (#478)
1 parent 9ea8263 commit eb67196

File tree

2 files changed

+153
-0
lines changed

2 files changed

+153
-0
lines changed

Examples/Docs/Sources/AsyncExamples/main.swift

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,3 +147,81 @@ private func changeStreams() throws {
147147
// End Changestream Example 4
148148
}
149149
}
150+
151+
/// Examples used for the MongoDB documentation on transactions.
152+
/// - SeeAlso: https://docs.mongodb.com/manual/core/transactions-in-applications/
153+
private func transactions() throws {
154+
let elg = MultiThreadedEventLoopGroup(numberOfThreads: 1)
155+
let client = try MongoClient(using: elg)
156+
157+
// Start Transactions Into Example 1
158+
func updateEmployeeInfo(session: ClientSession) -> EventLoopFuture<Void> {
159+
let employees = client.db("hr").collection("employees")
160+
let events = client.db("reporting").collection("events")
161+
162+
let options = TransactionOptions(readConcern: .snapshot, writeConcern: .majority)
163+
return session.startTransaction(options: options).flatMap {
164+
employees.updateOne(
165+
filter: ["employee": 3],
166+
update: ["$set": ["status": "Inactive"]],
167+
session: session
168+
).flatMap { _ in
169+
events.insertOne(["employee": 3, "status": ["new": "Inactive", "old": "Active"]])
170+
}.flatMapError { error in
171+
print("Caught error during transaction, aborting")
172+
return session.abortTransaction().flatMapThrowing { _ in
173+
throw error
174+
}
175+
}
176+
}.flatMap { _ in
177+
commitWithRetry(session: session)
178+
}
179+
}
180+
// End Transactions Intro Example 1
181+
182+
// Start Transactions Retry Example 1
183+
func runTransactionWithRetry(
184+
session: ClientSession,
185+
txnFunc: @escaping (ClientSession) -> EventLoopFuture<Void>
186+
) -> EventLoopFuture<Void> {
187+
let txnFuture = txnFunc(session)
188+
let eventLoop = txnFuture.eventLoop
189+
return txnFuture.flatMapError { error in
190+
guard
191+
let labeledError = error as? LabeledError,
192+
labeledError.errorLabels?.contains("TransientTransactionError") == true
193+
else {
194+
return eventLoop.makeFailedFuture(error)
195+
}
196+
print("TransientTransactionError, retrying transaction...")
197+
return runTransactionWithRetry(session: session, txnFunc: txnFunc)
198+
}
199+
}
200+
// End Transactions Retry Example 1
201+
202+
// Start Transactions Retry Example 2
203+
func commitWithRetry(session: ClientSession) -> EventLoopFuture<Void> {
204+
let commitFuture = session.commitTransaction()
205+
let eventLoop = commitFuture.eventLoop
206+
return commitFuture.flatMapError { error in
207+
guard
208+
let labeledError = error as? LabeledError,
209+
labeledError.errorLabels?.contains("UnknownTransactionCommitResult") == true
210+
else {
211+
print("Error during commit...")
212+
return eventLoop.makeFailedFuture(error)
213+
}
214+
print("UnknownTransactionCommitResult, retrying commit operation...")
215+
return commitWithRetry(session: session)
216+
}
217+
}
218+
// End Transactions Retry Example 2
219+
220+
// Start Transactions Retry Example 3
221+
try client.withSession { session in
222+
runTransactionWithRetry(session: session, txnFunc: updateEmployeeInfo).flatMapErrorThrowing { _ in
223+
// do something with error
224+
}
225+
}.wait()
226+
// End Transactions Retry Example 3
227+
}

Examples/Docs/Sources/SyncExamples/main.swift

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,3 +90,78 @@ private func changeStreams() throws {
9090
// End Changestream Example 4
9191
}
9292
}
93+
94+
/// Examples used for the MongoDB documentation on transactions.
95+
/// - SeeAlso: https://docs.mongodb.com/manual/core/transactions-in-applications/
96+
private func transactions() throws {
97+
// Start Transactions Intro Example 1
98+
func updateEmployeeInfo(session: ClientSession) throws {
99+
let employees = session.client.db("hr").collection("employees")
100+
let events = session.client.db("reporting").collection("events")
101+
102+
do {
103+
try employees.updateOne(filter: ["employee": 3], update: ["$set": ["status": "Inactive"]], session: session)
104+
try events.insertOne(["employee": 3, "status": ["new": "Inactive", "old": "Active"]], session: session)
105+
} catch {
106+
print("Caught error during transaction, aborting")
107+
try session.abortTransaction()
108+
throw error
109+
}
110+
try commitWithRetry(session: session)
111+
}
112+
// End Transactions Intro Example 1
113+
114+
// Start Transactions Retry Example 1
115+
func runTransactionWithRetry(session: ClientSession, txnFunc: @escaping (ClientSession) throws -> Void) throws {
116+
while true {
117+
do {
118+
return try txnFunc(session) // performs transaction
119+
} catch {
120+
print("Transaction aborted. Caught exception during transaction.")
121+
guard
122+
let labeledError = error as? LabeledError,
123+
labeledError.errorLabels?.contains("TransientTransactionError") == true
124+
else {
125+
throw error
126+
}
127+
// If transient error, retry the whole transaction
128+
print("TransientTransactionError, retrying transaction ...")
129+
continue
130+
}
131+
}
132+
}
133+
// End Transactions Retry Example 1
134+
135+
// Start Transactions Retry Example 2
136+
func commitWithRetry(session: ClientSession) throws {
137+
while true {
138+
do {
139+
try session.commitTransaction() // Uses write concern set at transaction start
140+
print("Transaction committed.")
141+
break
142+
} catch {
143+
guard
144+
let labeledError = error as? LabeledError,
145+
labeledError.errorLabels?.contains("UnknownTransactionCommitResult") == true
146+
else {
147+
print("Error during commit ...")
148+
throw error
149+
}
150+
print("UnknownTransactionCommitResult, retrying commit operation ...")
151+
continue
152+
}
153+
}
154+
}
155+
// End Transactions Retry Example 2
156+
157+
let client = try MongoClient()
158+
// Start Transactions Retry Example 3
159+
client.withSession { session in
160+
do {
161+
try runTransactionWithRetry(session: session, txnFunc: updateEmployeeInfo)
162+
} catch {
163+
// do something with error
164+
}
165+
}
166+
// End Transactions Retry Example 3
167+
}

0 commit comments

Comments
 (0)