Skip to content

Commit 08c79d2

Browse files
FennemAIJelteF
authored andcommitted
Retry serialization failures only once
The refresh only writes once per rollover, so once the request that won the race has committed, a retry has nothing left to conflict with. If that single retry still fails, something else is wrong and it's better to surface the error than to keep rerunning the whole view.
1 parent 9042f90 commit 08c79d2

2 files changed

Lines changed: 12 additions & 15 deletions

File tree

‎pgcommitfest/commitfest/tests/test_retry_on_serialization_failure.py‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,9 @@ def _pg_error(pgcode):
1818
@pytest.mark.parametrize(
1919
"pgcode,failures,expected_calls",
2020
[
21-
("40001", 2, 3), # serialization failure, recovers
21+
("40001", 1, 2), # serialization failure, recovers
2222
("40P01", 1, 2), # deadlock, recovers
23-
("40001", 99, 5), # persistent failure, gives up after 5 attempts
23+
("40001", 99, 2), # persistent failure, gives up after one retry
2424
("57014", 99, 1), # query_canceled is not transient, no retry
2525
],
2626
)

‎pgcommitfest/commitfest/views.py‎

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -77,19 +77,16 @@ def retry_on_serialization_failure(view_func):
7777

7878
@functools.wraps(view_func)
7979
def wrapper(*args, **kwargs):
80-
# A handful of attempts is plenty: the refresh only writes once per
81-
# rollover, so after the first one commits there is nothing left to
82-
# conflict with.
83-
last_attempt = 4
84-
for attempt in range(last_attempt + 1):
85-
try:
86-
return view_func(*args, **kwargs)
87-
except OperationalError as e:
88-
if (
89-
attempt == last_attempt
90-
or getattr(e.__cause__, "pgcode", None) not in RETRYABLE_PGCODES
91-
):
92-
raise
80+
try:
81+
return view_func(*args, **kwargs)
82+
except OperationalError as e:
83+
if getattr(e.__cause__, "pgcode", None) not in RETRYABLE_PGCODES:
84+
raise
85+
# A single retry is enough: the refresh only writes once per rollover,
86+
# so after the winning request commits there is nothing left to
87+
# conflict with. If the retry fails anyway, something else is going on
88+
# and we'd rather surface the error than keep hammering the database.
89+
return view_func(*args, **kwargs)
9390

9491
return wrapper
9592

0 commit comments

Comments
 (0)