Repository: prisma/prisma
File: packages/client-engine-runtime/src/transaction-manager/transaction-manager.ts (TypeScript)

Code before:
      } else {
        // Transaction was already committed or rolled back when timeout happened.
        // Should normally not happen as timeout is cancelled when transaction is committed or rolled back.
        // No further action needed though.
        debug('Transaction already committed or rolled back when timeout happened.', transactionId)
      }
    }, timeout)

    timer?.unref?.()
    return timer
  }

  async #closeTransaction(tx: TransactionWrapper, status: 'committed' | 'rolled_back' | 'timed_out'): Promise<void> {
    const createClosingPromise = async () => {
      debug('Closing transaction.', { transactionId: tx.id, status })
      try {
        if (tx.transaction && status === 'committed') {
          if (tx.transaction.options.usePhantomQuery) {
            await this.#withQuerySpanAndEvent(PHANTOM_COMMIT_QUERY(), tx.transaction, () => tx.transaction!.commit())
          } else {
            const query = COMMIT_QUERY()
            try {
              await this.#withQuerySpanAndEvent(query, tx.transaction, () => tx.transaction!.executeRaw(query))
            } finally {
              await tx.transaction.commit()
            }
          }
        } else if (tx.transaction) {
          if (tx.transaction.options.usePhantomQuery) {
            await this.#withQuerySpanAndEvent(PHANTOM_ROLLBACK_QUERY(), tx.transaction, () =>
              tx.transaction!.rollback(),
            )
          } else {
            const query = ROLLBACK_QUERY()
            try {
              await this.#withQuerySpanAndEvent(query, tx.transaction, () => tx.transaction!.executeRaw(query))
            } finally {
              await tx.transaction.rollback()
            }
          }
        }
      } finally {
        tx.status = status
        clearTimeout(tx.timer)
        tx.timer = undefined

        this.transactions.delete(tx.id)

        this.closedTransactions.push(tx)
        if (this.closedTransactions.length > MAX_CLOSED_TRANSACTIONS) {
          this.closedTransactions.shift()

Review comment (suggestion):
should it rather be something like this?

```suggestion
            try {
              await this.#withQuerySpanAndEvent(query, tx.transaction, () => tx.transaction!.executeRaw(query))
            } catch (err) {
              await tx.transaction.rollback().finally(() => Promise.reject(err))
            }
            await tx.transaction.commit()
```

Code after:
      } else {
        // Transaction was already committed or rolled back when timeout happened.
        // Should normally not happen as timeout is cancelled when transaction is committed or rolled back.
        // No further action needed though.
        debug('Transaction already committed or rolled back when timeout happened.', transactionId)
      }
    }, timeout)

    timer?.unref?.()
    return timer
  }

  async #closeTransaction(tx: TransactionWrapper, status: 'committed' | 'rolled_back' | 'timed_out'): Promise<void> {
    const createClosingPromise = async () => {
      debug('Closing transaction.', { transactionId: tx.id, status })
      try {
        if (tx.transaction && status === 'committed') {
          if (tx.transaction.options.usePhantomQuery) {
            await this.#withQuerySpanAndEvent(PHANTOM_COMMIT_QUERY(), tx.transaction, () => tx.transaction!.commit())
          } else {
            const query = COMMIT_QUERY()
            await this.#withQuerySpanAndEvent(query, tx.transaction, () => tx.transaction!.executeRaw(query)).then(
              () => tx.transaction!.commit(),
              (err) => {
                const fail = () => Promise.reject(err)
                return tx.transaction!.rollback().then(fail, fail)
              },
            )
          }
        } else if (tx.transaction) {
          if (tx.transaction.options.usePhantomQuery) {
            await this.#withQuerySpanAndEvent(PHANTOM_ROLLBACK_QUERY(), tx.transaction, () =>
              tx.transaction!.rollback(),
            )
          } else {
            const query = ROLLBACK_QUERY()
            try {
              await this.#withQuerySpanAndEvent(query, tx.transaction, () => tx.transaction!.executeRaw(query))
            } finally {
              await tx.transaction.rollback()
            }
          }
        }
      } finally {
        tx.status = status
        clearTimeout(tx.timer)
        tx.timer = undefined

        this.transactions.delete(tx.id)

        this.closedTransactions.push(tx)