summary refs log tree commit diff
path: root/synapse/federation
diff options
context:
space:
mode:
authorDavid Robertson <davidr@element.io>2022-10-06 19:17:50 +0100
committerGitHub <noreply@github.com>2022-10-06 18:17:50 +0000
commitcb20b885cb4bd1648581dd043a184d86fc8c7a00 (patch)
tree20ffd08e96133128eb1c363fc00bc5379642ed3c /synapse/federation
parentMerge tag 'v1.69.0rc2' into develop (diff)
downloadsynapse-cb20b885cb4bd1648581dd043a184d86fc8c7a00.tar.xz
Always close _all_ `ijson` coroutines, even if doing so raises Exceptions (#14065)
Diffstat (limited to 'synapse/federation')
-rw-r--r--synapse/federation/transport/client.py29
1 files changed, 25 insertions, 4 deletions
diff --git a/synapse/federation/transport/client.py b/synapse/federation/transport/client.py
index 32074b8ca6..cd39d4d111 100644
--- a/synapse/federation/transport/client.py
+++ b/synapse/federation/transport/client.py
@@ -45,6 +45,7 @@ from synapse.federation.units import Transaction
 from synapse.http.matrixfederationclient import ByteParser
 from synapse.http.types import QueryParams
 from synapse.types import JsonDict
+from synapse.util import ExceptionBundle
 
 logger = logging.getLogger(__name__)
 
@@ -926,8 +927,7 @@ class SendJoinParser(ByteParser[SendJoinResponse]):
         return len(data)
 
     def finish(self) -> SendJoinResponse:
-        for c in self._coros:
-            c.close()
+        _close_coros(self._coros)
 
         if self._response.event_dict:
             self._response.event = make_event_from_dict(
@@ -970,6 +970,27 @@ class _StateParser(ByteParser[StateRequestResponse]):
         return len(data)
 
     def finish(self) -> StateRequestResponse:
-        for c in self._coros:
-            c.close()
+        _close_coros(self._coros)
         return self._response
+
+
+def _close_coros(coros: Iterable[Generator[None, bytes, None]]) -> None:
+    """Close each of the given coroutines.
+
+    Always calls .close() on each coroutine, even if doing so raises an exception.
+    Any exceptions raised are aggregated into an ExceptionBundle.
+
+    :raises ExceptionBundle: if at least one coroutine fails to close.
+    """
+    exceptions = []
+    for c in coros:
+        try:
+            c.close()
+        except Exception as e:
+            exceptions.append(e)
+
+    if exceptions:
+        # raise from the first exception so that the traceback has slightly more context
+        raise ExceptionBundle(
+            f"There were {len(exceptions)} errors closing coroutines", exceptions
+        ) from exceptions[0]