Skip to content

Commit cdf8c83

Browse files
authored
Don't retry a failed commit (#517)
* Don't retry failed commit * Introduce new public error: IncompleteCommit * Import clean-ups
1 parent f6b0254 commit cdf8c83

File tree

8 files changed

+45
-48
lines changed

8 files changed

+45
-48
lines changed

neo4j/_exceptions.py

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -174,14 +174,6 @@ def transaction(self):
174174
return None
175175

176176

177-
class BoltIncompleteCommitError(BoltError):
178-
""" Raised when a disconnection occurs while still waiting for a commit
179-
response. For non-idempotent write transactions, this leaves the data
180-
in an unknown state with regard to whether the transaction completed
181-
successfully or not.
182-
"""
183-
184-
185177
class BoltProtocolError(BoltError):
186178
""" Raised when an unexpected or unsupported protocol event occurs.
187-
"""
179+
"""

neo4j/exceptions.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
+ RoutingServiceUnavailable
4646
+ WriteServiceUnavailable
4747
+ ReadServiceUnavailable
48+
+ IncompleteCommit
4849
+ ConfigurationError
4950
+ AuthConfigurationError
5051
+ CertificateConfigurationError
@@ -60,7 +61,6 @@
6061
+ BoltConnectionBroken
6162
+ BoltConnectionClosed
6263
+ BoltFailure
63-
+ BoltIncompleteCommitError
6464
+ BoltProtocolError
6565
+ Bolt*
6666
@@ -286,6 +286,16 @@ class ReadServiceUnavailable(ServiceUnavailable):
286286
"""
287287

288288

289+
class IncompleteCommit(ServiceUnavailable):
290+
""" Raised when the client looses connection while committing a transaction
291+
292+
Raised when a disconnection occurs while still waiting for a commit
293+
response. For non-idempotent write transactions, this leaves the data
294+
in an unknown state with regard to whether the transaction completed
295+
successfully or not.
296+
"""
297+
298+
289299
class ResultConsumedError(DriverError):
290300
""" Raised when trying to access records after the records have been consumed.
291301
"""

neo4j/io/_bolt3.py

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -35,18 +35,15 @@
3535
from neo4j.meta import get_user_agent
3636
from neo4j.exceptions import (
3737
AuthError,
38-
ServiceUnavailable,
3938
DatabaseUnavailable,
40-
NotALeader,
39+
ConfigurationError,
4140
ForbiddenOnReadOnlyDatabase,
41+
IncompleteCommit,
42+
NotALeader,
43+
ServiceUnavailable,
4244
SessionExpired,
43-
ConfigurationError,
44-
UnsupportedServerProduct,
45-
)
46-
from neo4j._exceptions import (
47-
BoltIncompleteCommitError,
48-
BoltProtocolError,
4945
)
46+
from neo4j._exceptions import BoltProtocolError
5047
from neo4j.packstream import (
5148
Unpacker,
5249
Packer,
@@ -406,9 +403,9 @@ def _set_defunct(self, error=None):
406403
for response in self.responses:
407404
if isinstance(response, CommitResponse):
408405
if error:
409-
raise BoltIncompleteCommitError(message, address=None) from error
406+
raise IncompleteCommit(message) from error
410407
else:
411-
raise BoltIncompleteCommitError(message, address=None)
408+
raise IncompleteCommit(message)
412409

413410
if direct_driver:
414411
if error:

neo4j/io/_bolt4.py

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -36,16 +36,14 @@
3636
from neo4j.meta import get_user_agent
3737
from neo4j.exceptions import (
3838
AuthError,
39-
ServiceUnavailable,
4039
DatabaseUnavailable,
41-
NotALeader,
4240
ForbiddenOnReadOnlyDatabase,
41+
IncompleteCommit,
42+
NotALeader,
43+
ServiceUnavailable,
4344
SessionExpired,
4445
)
45-
from neo4j._exceptions import (
46-
BoltIncompleteCommitError,
47-
BoltProtocolError,
48-
)
46+
from neo4j._exceptions import BoltProtocolError
4947
from neo4j.packstream import (
5048
Unpacker,
5149
Packer,
@@ -417,9 +415,9 @@ def _set_defunct(self, error=None):
417415
for response in self.responses:
418416
if isinstance(response, CommitResponse):
419417
if error:
420-
raise BoltIncompleteCommitError(message, address=None) from error
418+
raise IncompleteCommit(message) from error
421419
else:
422-
raise BoltIncompleteCommitError(message, address=None)
420+
raise IncompleteCommit(message)
423421

424422
if direct_driver:
425423
if error:

neo4j/work/simple.py

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -19,29 +19,31 @@
1919
# limitations under the License.
2020

2121

22-
from collections import deque
2322
from logging import getLogger
2423
from random import random
25-
from time import perf_counter, sleep
26-
from warnings import warn
24+
from time import (
25+
perf_counter,
26+
sleep,
27+
)
2728

2829
from neo4j.conf import SessionConfig
29-
from neo4j.api import READ_ACCESS, WRITE_ACCESS
30-
from neo4j.data import DataHydrator, DataDehydrator
30+
from neo4j.api import (
31+
READ_ACCESS,
32+
WRITE_ACCESS,
33+
)
34+
from neo4j.data import DataHydrator
3135
from neo4j.exceptions import (
36+
ClientError,
37+
IncompleteCommit,
3238
Neo4jError,
3339
ServiceUnavailable,
34-
TransientError,
3540
SessionExpired,
41+
TransientError,
3642
TransactionError,
37-
ClientError,
3843
)
39-
from neo4j._exceptions import BoltIncompleteCommitError
4044
from neo4j.work import Workspace
41-
from neo4j.work.summary import ResultSummary
42-
from neo4j.work.transaction import Transaction
4345
from neo4j.work.result import Result
44-
from neo4j.io._bolt3 import Bolt3
46+
from neo4j.work.transaction import Transaction
4547

4648
log = getLogger("neo4j")
4749

@@ -317,6 +319,8 @@ def _run_transaction(self, access_mode, transaction_function, *args, **kwargs):
317319
raise
318320
else:
319321
tx.commit()
322+
except IncompleteCommit:
323+
raise
320324
except (ServiceUnavailable, SessionExpired) as error:
321325
errors.append(error)
322326
self._disconnect()

neo4j/work/transaction.py

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,8 @@
2121

2222
from neo4j.work.result import Result
2323
from neo4j.data import DataHydrator
24-
from neo4j._exceptions import BoltIncompleteCommitError
2524
from neo4j.exceptions import (
26-
ServiceUnavailable,
25+
IncompleteCommit,
2726
TransactionError,
2827
)
2928

@@ -132,13 +131,10 @@ def commit(self):
132131
self._connection.commit(on_success=metadata.update)
133132
self._connection.send_all()
134133
self._connection.fetch_all()
135-
except BoltIncompleteCommitError:
134+
self._bookmark = metadata.get("bookmark")
135+
finally:
136136
self._closed = True
137137
self._on_closed()
138-
raise ServiceUnavailable("Connection closed during commit")
139-
self._bookmark = metadata.get("bookmark")
140-
self._closed = True
141-
self._on_closed()
142138

143139
return self._bookmark
144140

tests/unit/test_api.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
from uuid import uuid4
2424

2525
import neo4j.api
26-
from neo4j.work.simple import DataDehydrator
26+
from neo4j.data import DataDehydrator
2727
from neo4j.exceptions import (
2828
ConfigurationError,
2929
)

tests/unit/test_exceptions.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
RoutingServiceUnavailable,
4343
WriteServiceUnavailable,
4444
ReadServiceUnavailable,
45+
IncompleteCommit,
4546
ConfigurationError,
4647
AuthConfigurationError,
4748
CertificateConfigurationError,
@@ -60,7 +61,6 @@
6061
BoltConnectionBroken,
6162
BoltConnectionClosed,
6263
BoltFailure,
63-
BoltIncompleteCommitError,
6464
BoltProtocolError,
6565
)
6666

0 commit comments

Comments
 (0)