Repository navigation
Commit d7a37dd
authored
Fix application error desyncing auto-commit result (#1333)
Raising an application error inside a `with driver.session() as s:` block that
has an on-going auto-commit transaction, i.e., `res = s.run(...)` has been
called but `res` has not yet been consumed will lead to the session returning
its backing connection to the pool (where it can be picked up by other sessions)
without properly finalizing the auto-commit transaction. `res` then holds a
reference to (and potentially uses) a connection that is no longer bound to
`res`'s parent session. This can lead to all sorts of misbehavior (from data
races casing protocol errors all the way to reading records of another query).
Reproducer:
```python
from __future__ import annotations
from neo4j import GraphDatabase, Result
from neo4j.debug import watch
watch("neo4j")
URL = "bolt://localhost:7687"
AUTH = ("neo4j", "pass")
DB = "neo4j"
class MyError(RuntimeError):
pass
def inspect_records(result: neo4j.Result, n: int, stream_name: str):
print(f"\ninspecting stream {stream_name}: fetching {n} records")
records = [record["res"] for record in result.fetch(n)]
print(f"got {len(records)} records")
for record in records:
print(repr(record))
assert isinstance(record, str) and record.startswith(f"{stream_name}-")
def main():
range_top = 10
query = (
'UNWIND range(1, $upper) AS i '
'RETURN "res" + $n + "-" + apoc.text.lpad(toString(i), $pad, "0") '
'AS res'
)
params = {"upper": range_top, "pad": len(str(range_top))}
with GraphDatabase.driver(URL, auth=AUTH) as driver:
fetch_size = 2
try:
with (
driver.session(database=DB, fetch_size=fetch_size) as session
):
res1 = session.run(query, parameters={**params, "n": 1})
inspect_records(res1, 3, "res1")
raise MyError("test error")
except MyError as e:
print(f"Caught MyError: {e}")
with (
driver.session(database=DB, fetch_size=fetch_size) as session
):
res2 = session.run(query, parameters={**params, "n": 2})
inspect_records(res2, 3, "res2")
# !!! res1 now reading records from res2
inspect_records(res1, 3, "res1")
if __name__ == "__main__":
main()
```1 parent c10e272 commit d7a37dd
4 files changed
Lines changed: 146 additions & 46 deletions
File tree
- src/neo4j
- _async/work
- _sync/work
- tests/unit
- async_/work
- sync/work
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
92 | 92 | | |
93 | 93 | | |
94 | 94 | | |
95 | | - | |
96 | | - | |
97 | | - | |
98 | 95 | | |
99 | 96 | | |
100 | 97 | | |
| |||
113 | 110 | | |
114 | 111 | | |
115 | 112 | | |
116 | | - | |
117 | | - | |
118 | | - | |
119 | | - | |
120 | | - | |
121 | | - | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
122 | 119 | | |
123 | 120 | | |
124 | 121 | | |
| |||
195 | 192 | | |
196 | 193 | | |
197 | 194 | | |
198 | | - | |
| 195 | + | |
199 | 196 | | |
| 197 | + | |
| 198 | + | |
| 199 | + | |
200 | 200 | | |
201 | | - | |
202 | | - | |
203 | | - | |
204 | | - | |
205 | | - | |
| 201 | + | |
| 202 | + | |
| 203 | + | |
| 204 | + | |
| 205 | + | |
| 206 | + | |
| 207 | + | |
| 208 | + | |
| 209 | + | |
206 | 210 | | |
207 | 211 | | |
208 | 212 | | |
| |||
215 | 219 | | |
216 | 220 | | |
217 | 221 | | |
218 | | - | |
219 | | - | |
220 | | - | |
221 | | - | |
222 | | - | |
223 | | - | |
224 | | - | |
| 222 | + | |
| 223 | + | |
| 224 | + | |
| 225 | + | |
| 226 | + | |
| 227 | + | |
225 | 228 | | |
226 | 229 | | |
227 | 230 | | |
228 | 231 | | |
229 | | - | |
230 | 232 | | |
231 | 233 | | |
232 | 234 | | |
| |||
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
48 | 48 | | |
49 | 49 | | |
50 | 50 | | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
51 | 55 | | |
52 | 56 | | |
53 | 57 | | |
| |||
1025 | 1029 | | |
1026 | 1030 | | |
1027 | 1031 | | |
| 1032 | + | |
| 1033 | + | |
| 1034 | + | |
| 1035 | + | |
| 1036 | + | |
| 1037 | + | |
| 1038 | + | |
| 1039 | + | |
| 1040 | + | |
| 1041 | + | |
| 1042 | + | |
| 1043 | + | |
| 1044 | + | |
| 1045 | + | |
| 1046 | + | |
| 1047 | + | |
| 1048 | + | |
| 1049 | + | |
| 1050 | + | |
| 1051 | + | |
| 1052 | + | |
| 1053 | + | |
| 1054 | + | |
| 1055 | + | |
| 1056 | + | |
| 1057 | + | |
| 1058 | + | |
| 1059 | + | |
| 1060 | + | |
| 1061 | + | |
| 1062 | + | |
| 1063 | + | |
| 1064 | + | |
| 1065 | + | |
| 1066 | + | |
| 1067 | + | |
| 1068 | + | |
| 1069 | + | |
| 1070 | + | |
| 1071 | + | |
| 1072 | + | |
| 1073 | + | |
| 1074 | + | |
| 1075 | + | |
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
0 commit comments