diff --git a/changelog.d/3845.bugfix b/changelog.d/3845.bugfix
new file mode 100644
index 0000000000..5b7e8f1934
--- /dev/null
+++ b/changelog.d/3845.bugfix
@@ -0,0 +1 @@
+Fix outbound requests occasionally wedging, which can result in federation breaking between servers.
diff --git a/synapse/http/matrixfederationclient.py b/synapse/http/matrixfederationclient.py
index 6a1fc8ca55..f9a1fbf95d 100644
--- a/synapse/http/matrixfederationclient.py
+++ b/synapse/http/matrixfederationclient.py
@@ -280,7 +280,10 @@ class MatrixFederationHttpClient(object):
# :'(
# Update transactions table?
with logcontext.PreserveLoggingContext():
- body = yield treq.content(response)
+ body = yield self._timeout_deferred(
+ treq.content(response),
+ timeout,
+ )
raise HttpResponseException(
response.code, response.phrase, body
)
@@ -394,7 +397,10 @@ class MatrixFederationHttpClient(object):
check_content_type_is_json(response.headers)
with logcontext.PreserveLoggingContext():
- body = yield treq.json_content(response)
+ body = yield self._timeout_deferred(
+ treq.json_content(response),
+ timeout,
+ )
defer.returnValue(body)
@defer.inlineCallbacks
@@ -444,7 +450,10 @@ class MatrixFederationHttpClient(object):
check_content_type_is_json(response.headers)
with logcontext.PreserveLoggingContext():
- body = yield treq.json_content(response)
+ body = yield self._timeout_deferred(
+ treq.json_content(response),
+ timeout,
+ )
defer.returnValue(body)
@@ -496,7 +505,10 @@ class MatrixFederationHttpClient(object):
check_content_type_is_json(response.headers)
with logcontext.PreserveLoggingContext():
- body = yield treq.json_content(response)
+ body = yield self._timeout_deferred(
+ treq.json_content(response),
+ timeout,
+ )
defer.returnValue(body)
@@ -543,7 +555,10 @@ class MatrixFederationHttpClient(object):
check_content_type_is_json(response.headers)
with logcontext.PreserveLoggingContext():
- body = yield treq.json_content(response)
+ body = yield self._timeout_deferred(
+ treq.json_content(response),
+ timeout,
+ )
defer.returnValue(body)
@@ -585,8 +600,10 @@ class MatrixFederationHttpClient(object):
try:
with logcontext.PreserveLoggingContext():
- length = yield _readBodyToFile(
- response, output_stream, max_size
+ length = yield self._timeout_deferred(
+ _readBodyToFile(
+ response, output_stream, max_size
+ ),
)
except Exception:
logger.exception("Failed to download body")
@@ -594,6 +611,27 @@ class MatrixFederationHttpClient(object):
defer.returnValue((length, headers))
+ def _timeout_deferred(self, deferred, timeout_ms=None):
+ """Times the deferred out after `timeout_ms` ms
+
+ Args:
+ deferred (Deferred)
+ timeout_ms (int|None): Timeout in milliseconds. If None defaults
+ to 60 seconds.
+
+ Returns:
+ Deferred
+ """
+
+ add_timeout_to_deferred(
+ deferred,
+ timeout_ms / 1000. if timeout_ms else 60,
+ self.hs.get_reactor(),
+ cancelled_to_request_timed_out_error,
+ )
+
+ return deferred
+
class _ReadBodyToFileProtocol(protocol.Protocol):
def __init__(self, stream, deferred, max_size):
|