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
49 changes: 4 additions & 45 deletions async_postgres/pg_client/transaction.nim
Original file line number Diff line number Diff line change
Expand Up @@ -321,37 +321,15 @@ macro withTransaction*(conn: PgConnection, args: varargs[untyped]): untyped =
let connExpr = conn
let connSym = genSym(nskLet, "conn")
let eSym = genSym(nskLet, "e")
let cleanupErrSym = genSym(nskLet, "cleanupErr")
let tsInTxSym = bindSym"tsInTransaction"
let tsInFailedSym = bindSym"tsInFailedTransaction"
let csReadySym = bindSym"csReady"
let (fireCleanupSkippedSym, csrConnInvalidatedSym, csrCleanupFailedSym) =
bindCleanupSkippedSyms()
let ckTxRollbackSym = bindSym"ckTxRollback"
let bodyCleanup = buildRollbackCleanup(connSym, txTimeout)
result = quote:
let `connSym` = `connExpr`
try:
discard await `connSym`.simpleExec(`beginSql`, timeout = `txTimeout`)
`body`
discard await `connSym`.simpleExec("COMMIT", timeout = `txTimeout`)
except CatchableError as `eSym`:
# Only ROLLBACK if the server is still in a transaction AND the connection
# is usable. After a failed COMMIT, PostgreSQL has already ended the
# transaction (txStatus = tsIdle), so an extra ROLLBACK would just emit
# "no transaction in progress". On per-call timeout the connection is
# csClosed but txStatus is stale (no RFQ received) — the state guard
# avoids dispatching a ROLLBACK that would fail at checkReady(). Both
# the csClosed skip and any swallowed inner-ROLLBACK failure are
# reported via `onCleanupSkipped` so the timeout path is not silent.
if `connSym`.state != `csReadySym`:
`fireCleanupSkippedSym`(`connSym`, `ckTxRollbackSym`, `csrConnInvalidatedSym`)
elif `connSym`.txStatus in {`tsInTxSym`, `tsInFailedSym`}:
try:
discard await `connSym`.simpleExec("ROLLBACK", timeout = `txTimeout`)
except CatchableError as `cleanupErrSym`:
`fireCleanupSkippedSym`(
`connSym`, `ckTxRollbackSym`, `csrCleanupFailedSym`, `cleanupErrSym`
)
`bodyCleanup`
raise `eSym`

macro withTransactionRetry*(
Expand Down Expand Up @@ -606,21 +584,15 @@ macro withTransactionDeadline*(conn: PgConnection, args: varargs[untyped]): unty
let connExpr = conn
let connSym = genSym(nskLet, "conn")
let eSym = genSym(nskLet, "e")
let cleanupErrSym = genSym(nskLet, "cleanupErr")
let totalDurSym = genSym(nskLet, "totalDur")
let deadlineMomentSym = genSym(nskLet, "deadlineMoment")
let bodyFnSym = genSym(nskProc, "txBodyDeadline")
let bodyFutSym = genSym(nskLet, "bodyFut")
let tsInTxSym = bindSym"tsInTransaction"
let tsInFailedSym = bindSym"tsInFailedTransaction"
let csReadySym = bindSym"csReady"
let timeoutErrSym = bindSym"AsyncTimeoutError"
let waitSym = bindSym"wait"
let remainingSym = bindSym"remainingDeadlineDuration"
let graceSym = bindSym"rollbackGrace"
let (fireCleanupSkippedSym, csrConnInvalidatedSym, csrCleanupFailedSym) =
bindCleanupSkippedSyms()
let ckTxRollbackSym = bindSym"ckTxRollback"
let bodyCleanup = buildRollbackCleanup(connSym, graceSym)
result = quote:
let `connSym` = `connExpr`
let `totalDurSym` = `deadline`
Expand Down Expand Up @@ -652,20 +624,7 @@ macro withTransactionDeadline*(conn: PgConnection, args: varargs[untyped]): unty
# PgTimeoutError — control does not return from this call.
`connSym`.invalidateOnTimeout("withTransactionDeadline exceeded")
except CatchableError as `eSym`:
# Skip ROLLBACK when the connection is already csClosed (e.g. a per-call
# timeout inside body invalidated it) — checkReady would just raise and
# the failure would be swallowed by the inner except. Both the
# csClosed skip and any swallowed inner-ROLLBACK failure are reported
# via `onCleanupSkipped`.
if `connSym`.state != `csReadySym`:
`fireCleanupSkippedSym`(`connSym`, `ckTxRollbackSym`, `csrConnInvalidatedSym`)
elif `connSym`.txStatus in {`tsInTxSym`, `tsInFailedSym`}:
try:
discard await `connSym`.simpleExec("ROLLBACK", timeout = `graceSym`)
except CatchableError as `cleanupErrSym`:
`fireCleanupSkippedSym`(
`connSym`, `ckTxRollbackSym`, `csrCleanupFailedSym`, `cleanupErrSym`
)
`bodyCleanup`
raise `eSym`

macro withTransactionRetryDeadline*(
Expand Down
52 changes: 4 additions & 48 deletions async_postgres/pg_pool.nim
Original file line number Diff line number Diff line change
Expand Up @@ -1701,15 +1701,8 @@ macro withTransaction*(pool: PgPool, args: varargs[untyped]): untyped =
let poolExpr = pool
let poolSym = genSym(nskLet, "pool")
let eSym = genSym(nskLet, "e")
let cleanupErrSym = genSym(nskLet, "cleanupErr")
let resetSessionSym = bindSym"resetSession"
let csReadySym = bindSym"csReady"
let tsInTxSym = bindSym"tsInTransaction"
let tsInFailedSym = bindSym"tsInFailedTransaction"
let fireCleanupSkippedSym = bindSym"fireCleanupSkipped"
let ckTxRollbackSym = bindSym"ckTxRollback"
let csrConnInvalidatedSym = bindSym"csrConnInvalidated"
let csrCleanupFailedSym = bindSym"csrCleanupFailed"
let bodyCleanup = buildRollbackCleanup(connIdent, txTimeout)
result = quote:
let `poolSym` = `poolExpr`
let `connIdent` = await `poolSym`.acquire()
Expand All @@ -1719,24 +1712,7 @@ macro withTransaction*(pool: PgPool, args: varargs[untyped]): untyped =
`body`
discard await `connIdent`.simpleExec("COMMIT", timeout = `txTimeout`)
except CatchableError as `eSym`:
# Mirror the per-call rationale from pg_client's `withTransaction`:
# skip ROLLBACK on an already-invalidated connection (per-call
# timeout marked it csClosed but txStatus may still be stale) and
# avoid a futile cleanup when the server has already ended the
# transaction. The csClosed skip and any swallowed inner-ROLLBACK
# failure are surfaced through `onCleanupSkipped` so the diagnostic
# asymmetry with the body-error path goes away.
if `connIdent`.state != `csReadySym`:
`fireCleanupSkippedSym`(
`connIdent`, `ckTxRollbackSym`, `csrConnInvalidatedSym`
)
elif `connIdent`.txStatus in {`tsInTxSym`, `tsInFailedSym`}:
try:
discard await `connIdent`.simpleExec("ROLLBACK", timeout = `txTimeout`)
except CatchableError as `cleanupErrSym`:
`fireCleanupSkippedSym`(
`connIdent`, `ckTxRollbackSym`, `csrCleanupFailedSym`, `cleanupErrSym`
)
`bodyCleanup`
raise `eSym`
finally:
await `resetSessionSym`(`poolSym`, `connIdent`)
Expand Down Expand Up @@ -1874,7 +1850,6 @@ macro withTransactionDeadline*(pool: PgPool, args: varargs[untyped]): untyped =
let poolExpr = pool
let poolSym = genSym(nskLet, "pool")
let eSym = genSym(nskLet, "e")
let cleanupErrSym = genSym(nskLet, "cleanupErr")
let totalDurSym = genSym(nskLet, "totalDur")
let deadlineMomentSym = genSym(nskLet, "deadlineMoment")
let bodyFnSym = genSym(nskProc, "poolTxBodyDeadline")
Expand All @@ -1886,17 +1861,12 @@ macro withTransactionDeadline*(pool: PgPool, args: varargs[untyped]): untyped =
let csReadySym = bindSym"csReady"
let csClosedSym = bindSym"csClosed"
let cancelNoWaitSym = bindSym"cancelNoWait"
let tsInTxSym = bindSym"tsInTransaction"
let tsInFailedSym = bindSym"tsInFailedTransaction"
let timeoutErrSym = bindSym"AsyncTimeoutError"
let waitSym = bindSym"wait"
let remainingSym = bindSym"remainingDeadlineDuration"
let graceSym = bindSym"rollbackGrace"
let invalidateSym = bindSym"invalidateOnTimeout"
let fireCleanupSkippedSym = bindSym"fireCleanupSkipped"
let ckTxRollbackSym = bindSym"ckTxRollback"
let csrConnInvalidatedSym = bindSym"csrConnInvalidated"
let csrCleanupFailedSym = bindSym"csrCleanupFailed"
let bodyCleanup = buildRollbackCleanup(connIdent, graceSym)

result = quote:
let `poolSym` = `poolExpr`
Expand All @@ -1917,21 +1887,7 @@ macro withTransactionDeadline*(pool: PgPool, args: varargs[untyped]): untyped =
"COMMIT", timeout = `remainingSym`(`deadlineMomentSym`)
)
except CatchableError as `eSym`:
# Mirror pg_client's `withTransactionDeadline`: skip ROLLBACK on a
# csClosed connection (per-call body timeout invalidated it) and
# report the skip / any swallowed inner-ROLLBACK failure through
# `onCleanupSkipped` so the timeout path is observable.
if `connIdent`.state != `csReadySym`:
`fireCleanupSkippedSym`(
`connIdent`, `ckTxRollbackSym`, `csrConnInvalidatedSym`
)
elif `connIdent`.txStatus in {`tsInTxSym`, `tsInFailedSym`}:
try:
discard await `connIdent`.simpleExec("ROLLBACK", timeout = `graceSym`)
except CatchableError as `cleanupErrSym`:
`fireCleanupSkippedSym`(
`connIdent`, `ckTxRollbackSym`, `csrCleanupFailedSym`, `cleanupErrSym`
)
`bodyCleanup`
raise `eSym`
except CancelledError as `cancelledSym`:
# Cancelled mid-request (chronos deadline): abort it server-side and
Expand Down