Compare commits

...

1 Commits

Author SHA1 Message Date
Dan Ribbens
43cdb45620 fix: mongodb multiple error rollback transaction 2023-11-22 11:53:45 -05:00
3 changed files with 30 additions and 14 deletions

View File

@@ -1,23 +1,27 @@
import type { RollbackTransaction } from 'payload/database'
export const rollbackTransaction: RollbackTransaction = async function rollbackTransaction(
id = '',
) {
export const rollbackTransaction: RollbackTransaction = function rollbackTransaction(id = '') {
// if multiple operations are using the same transaction, the first will flow through and delete the session.
// subsequent calls should be ignored.
if (!this.sessions[id]) {
return
}
// when session exists but is not inTransaction something unexpected is happening to the session
// when session exists but inTransaction is false, it is no longer used and can be deleted
if (!this.sessions[id].inTransaction()) {
this.payload.logger.warn('rollbackTransaction called when no transaction exists')
delete this.sessions[id]
return
}
// the first call for rollback should be aborted and deleted causing any other operations with the same transaction to fail
await this.sessions[id].abortTransaction()
await this.sessions[id].endSession()
try {
// null coalesce needed when rollback is called multiple times with the same id synchronously
this.sessions?.[id].abortTransaction().then(() => {
// not supported by DocumentDB
this.sessions?.[id].endSession()
})
} catch (e) {
// no action needed
}
delete this.sessions[id]
}

View File

@@ -151,7 +151,7 @@ export type BeginTransaction = (
options?: Record<string, unknown>,
) => Promise<null | number | string>
export type RollbackTransaction = (id: number | string) => Promise<void>
export type RollbackTransaction = (id: number | string) => Promise<void> | void
export type CommitTransaction = (id: number | string) => Promise<void>

View File

@@ -161,18 +161,30 @@ describe('database', () => {
},
req,
})
try {
await payload.create({
const promises = [
payload.create({
collection,
data: {
throwAfterChange: true,
title,
},
req,
})
} catch (error: unknown) {
// catch error and carry on
}),
// multiple documents should be able to fail without error
payload.create({
collection,
data: {
throwAfterChange: true,
title,
},
req,
}),
]
try {
await Promise.all(promises)
} catch (e) {
// catch errors and carry on
}
expect(req.transactionID).toBeFalsy()