|
| 1 | +import time |
| 2 | + |
1 | 3 | from django.db.backends.base.base import timezone_constructor
|
2 | 4 | from django.db.backends.postgresql.operations import (
|
3 | 5 | DatabaseOperations as PostgresDatabaseOperations,
|
4 | 6 | )
|
5 |
| -from django.db.backends.postgresql.psycopg_any import is_psycopg3 |
| 7 | +from django.db.backends.postgresql.psycopg_any import errors, is_psycopg3 |
| 8 | +from django.db.utils import OperationalError |
6 | 9 |
|
7 | 10 |
|
8 | 11 | class DatabaseOperations(PostgresDatabaseOperations):
|
@@ -72,6 +75,22 @@ def explain_query_prefix(self, format=None, **options):
|
72 | 75 | prefix += ' (%s)' % ', '.join(extra)
|
73 | 76 | return prefix
|
74 | 77 |
|
| 78 | + def execute_sql_flush(self, sql_list): |
| 79 | + # Retry TRUNCATE if it fails with a serialization error. |
| 80 | + num_retries = 10 |
| 81 | + initial_retry_delay = 0.5 # The initial retry delay, in seconds. |
| 82 | + backoff_ = 1.5 # For each retry, the last delay is multiplied by this. |
| 83 | + next_retry_delay = initial_retry_delay |
| 84 | + for retry in range(1, num_retries + 1): |
| 85 | + try: |
| 86 | + return super().execute_sql_flush(sql_list) |
| 87 | + except OperationalError as exc: |
| 88 | + if (not isinstance(exc.__cause__, errors.SerializationFailure) or |
| 89 | + retry >= num_retries): |
| 90 | + raise |
| 91 | + time.sleep(next_retry_delay) |
| 92 | + next_retry_delay *= backoff_ |
| 93 | + |
75 | 94 | def sql_flush(self, style, tables, *, reset_sequences=False, allow_cascade=False):
|
76 | 95 | # CockroachDB doesn't support resetting sequences.
|
77 | 96 | return super().sql_flush(style, tables, reset_sequences=False, allow_cascade=allow_cascade)
|
0 commit comments