fix(api): retry wrapped Neptune transient errors (#11996)

This commit is contained in:
Josema Camacho
2026-07-15 16:01:04 +02:00
committed by GitHub
parent 31b8ab9b4b
commit 07d7e9d5bb
2 changed files with 10 additions and 6 deletions
@@ -66,7 +66,7 @@ READ_EXCEPTION_CODES = [
"Neo.ClientError.Procedure.ProcedureNotFound",
]
CLIENT_STATEMENT_EXCEPTION_PREFIX = "Neo.ClientError.Statement."
RETRYABLE_WRITE_ERROR_PREFIXES = (
RETRYABLE_WRITE_ERROR_FRAGMENTS = (
"Operation failed due to conflicting concurrent operations",
"Operation terminated (deadline exceeded)",
)
@@ -78,7 +78,8 @@ SIGV4_TOKEN_LIFETIME_MINUTES = 4
def _is_retryable_write_error(exc: Exception) -> bool:
if not isinstance(exc, neo4j.exceptions.Neo4jError):
return False
return bool(exc.message and exc.message.startswith(RETRYABLE_WRITE_ERROR_PREFIXES))
message = exc.message or ""
return any(fragment in message for fragment in RETRYABLE_WRITE_ERROR_FRAGMENTS)
class NeptuneSink(SinkDatabase):
+7 -4
View File
@@ -332,9 +332,10 @@ class TestNeptuneRetryPolicy:
@pytest.mark.parametrize(
"message",
[
"Operation failed due to conflicting concurrent operations "
+ "(please retry), 0 transactions are currently rolling back.",
"Operation terminated (deadline exceeded)",
"Unexpected server exception 'Operation failed due to conflicting "
"concurrent operations (please retry), 0 transactions are currently "
"rolling back.'",
"Unexpected server exception 'Operation terminated (deadline exceeded)'",
],
)
def test_observed_transient_write_errors_are_retryable(self, message):
@@ -345,7 +346,9 @@ class TestNeptuneRetryPolicy:
def test_unrelated_database_error_is_not_retryable(self):
error = MagicMock(spec=neo4j.exceptions.Neo4jError)
error.message = "Operation terminated (out of memory)"
error.message = (
"Unexpected server exception 'Operation terminated (out of memory)'"
)
assert _is_retryable_write_error(error) is False