Skip to content
This repository was archived by the owner on Apr 26, 2024. It is now read-only.

Commit bb7a637

Browse files
authored
Close ijson coroutines ourselves instead of letting the GC close them (#12875)
Hopefully this means that exceptions raised due to truncated JSON get a sensible logging context and stack. Signed-off-by: Sean Quah <[email protected]>
1 parent 7b88f5a commit bb7a637

File tree

3 files changed

+19
-2
lines changed

3 files changed

+19
-2
lines changed

changelog.d/12875.bugfix

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Explicitly close `ijson` coroutines once we are done with them, instead of leaving the garbage collector to close them.

synapse/federation/transport/client.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1363,7 +1363,7 @@ class SendJoinParser(ByteParser[SendJoinResponse]):
13631363
def __init__(self, room_version: RoomVersion, v1_api: bool):
13641364
self._response = SendJoinResponse([], [], event_dict={})
13651365
self._room_version = room_version
1366-
self._coros = []
1366+
self._coros: List[Generator[None, bytes, None]] = []
13671367

13681368
# The V1 API has the shape of `[200, {...}]`, which we handle by
13691369
# prefixing with `item.*`.
@@ -1411,6 +1411,9 @@ def write(self, data: bytes) -> int:
14111411
return len(data)
14121412

14131413
def finish(self) -> SendJoinResponse:
1414+
for c in self._coros:
1415+
c.close()
1416+
14141417
if self._response.event_dict:
14151418
self._response.event = make_event_from_dict(
14161419
self._response.event_dict, self._room_version
@@ -1430,7 +1433,7 @@ class _StateParser(ByteParser[StateRequestResponse]):
14301433
def __init__(self, room_version: RoomVersion):
14311434
self._response = StateRequestResponse([], [])
14321435
self._room_version = room_version
1433-
self._coros = [
1436+
self._coros: List[Generator[None, bytes, None]] = [
14341437
ijson.items_coro(
14351438
_event_list_parser(room_version, self._response.state),
14361439
"pdus.item",
@@ -1449,4 +1452,6 @@ def write(self, data: bytes) -> int:
14491452
return len(data)
14501453

14511454
def finish(self) -> StateRequestResponse:
1455+
for c in self._coros:
1456+
c.close()
14521457
return self._response

synapse/http/matrixfederationclient.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,7 @@ async def _handle_response(
225225
if max_response_size is None:
226226
max_response_size = MAX_RESPONSE_SIZE
227227

228+
finished = False
228229
try:
229230
check_content_type_is(response.headers, parser.CONTENT_TYPE)
230231

@@ -233,6 +234,7 @@ async def _handle_response(
233234

234235
length = await make_deferred_yieldable(d)
235236

237+
finished = True
236238
value = parser.finish()
237239
except BodyExceededMaxSize as e:
238240
# The response was too big.
@@ -283,6 +285,15 @@ async def _handle_response(
283285
e,
284286
)
285287
raise
288+
finally:
289+
if not finished:
290+
# There was an exception and we didn't `finish()` the parse.
291+
# Let the parser know that it can free up any resources.
292+
try:
293+
parser.finish()
294+
except Exception:
295+
# Ignore any additional exceptions.
296+
pass
286297

287298
time_taken_secs = reactor.seconds() - start_ms / 1000
288299

0 commit comments

Comments
 (0)