Skip to content

Commit f75dfa6

Browse files
committed
fix #302, check transaction state before rollback
running rollback on failed or already rolled back transactions has no effect and asyncpg would throw exceptions
1 parent d074dc4 commit f75dfa6

File tree

3 files changed

+23
-8
lines changed

3 files changed

+23
-8
lines changed

gino/dialects/asyncpg.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import time
44

55
import asyncpg
6+
from asyncpg.transaction import TransactionState
67
from sqlalchemy import util, exc, sql
78
from sqlalchemy.dialects.postgresql import ( # noqa: F401
89
ARRAY,
@@ -242,6 +243,10 @@ async def commit(self):
242243
await self._tx.commit()
243244

244245
async def rollback(self):
246+
# noinspection PyProtectedMember
247+
if self._tx._state in (TransactionState.FAILED,
248+
TransactionState.ROLLEDBACK):
249+
return
245250
await self._tx.rollback()
246251

247252

gino/transaction.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -166,16 +166,16 @@ async def __aenter__(self):
166166
return self
167167

168168
async def __aexit__(self, ex_type, ex, ex_tb):
169-
try:
170-
is_break = ex_type is _Break
171-
if is_break and ex.commit:
172-
ex_type = None
173-
if ex_type is None:
169+
is_break = ex_type is _Break
170+
if is_break and ex.commit:
171+
ex_type = None
172+
if ex_type is None:
173+
try:
174174
await self._tx.commit()
175-
else:
175+
except Exception:
176176
await self._tx.rollback()
177-
except Exception:
177+
raise
178+
else:
178179
await self._tx.rollback()
179-
raise
180180
if is_break and ex.tx is self:
181181
return True

tests/test_transaction.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import pytest
2+
from asyncpg.transaction import TransactionState
23

34
from .models import db, User, qsize
45

@@ -249,3 +250,12 @@ async def test_base_exception(engine):
249250
except Exception:
250251
assert False, 'Should not reach here'
251252
assert False, 'Should not reach here'
253+
254+
255+
async def test_rollback_failed_transaction(engine):
256+
# for transaction whose state is rolled back or failed, rollback() won't
257+
# have any effect and shouldn't throw exceptions
258+
for state in (TransactionState.ROLLEDBACK, TransactionState.FAILED):
259+
async with engine.transaction() as tx:
260+
tx._tx._tx._state = state
261+
tx.raise_rollback()

0 commit comments

Comments
 (0)