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

Commit 5bf8e5f

Browse files
authored
Convert the well known resolver to async (#8214)
1 parent da77520 commit 5bf8e5f

File tree

5 files changed

+53
-34
lines changed

5 files changed

+53
-34
lines changed

changelog.d/8214.misc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Convert various parts of the codebase to async/await.

mypy.ini

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ files =
2828
synapse/handlers/saml_handler.py,
2929
synapse/handlers/sync.py,
3030
synapse/handlers/ui_auth,
31+
synapse/http/federation/well_known_resolver.py,
3132
synapse/http/server.py,
3233
synapse/http/site.py,
3334
synapse/logging/,

synapse/http/federation/matrix_federation_agent.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -134,8 +134,8 @@ def request(self, method, uri, headers=None, bodyProducer=None):
134134
and not _is_ip_literal(parsed_uri.hostname)
135135
and not parsed_uri.port
136136
):
137-
well_known_result = yield self._well_known_resolver.get_well_known(
138-
parsed_uri.hostname
137+
well_known_result = yield defer.ensureDeferred(
138+
self._well_known_resolver.get_well_known(parsed_uri.hostname)
139139
)
140140
delegated_server = well_known_result.delegated_server
141141

synapse/http/federation/well_known_resolver.py

Lines changed: 31 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,15 @@
1616
import logging
1717
import random
1818
import time
19+
from typing import Callable, Dict, Optional, Tuple
1920

2021
import attr
2122

2223
from twisted.internet import defer
2324
from twisted.web.client import RedirectAgent, readBody
2425
from twisted.web.http import stringToDatetime
2526
from twisted.web.http_headers import Headers
27+
from twisted.web.iweb import IResponse
2628

2729
from synapse.logging.context import make_deferred_yieldable
2830
from synapse.util import Clock, json_decoder
@@ -99,15 +101,14 @@ def __init__(
99101
self._well_known_agent = RedirectAgent(agent)
100102
self.user_agent = user_agent
101103

102-
@defer.inlineCallbacks
103-
def get_well_known(self, server_name):
104+
async def get_well_known(self, server_name: bytes) -> WellKnownLookupResult:
104105
"""Attempt to fetch and parse a .well-known file for the given server
105106
106107
Args:
107-
server_name (bytes): name of the server, from the requested url
108+
server_name: name of the server, from the requested url
108109
109110
Returns:
110-
Deferred[WellKnownLookupResult]: The result of the lookup
111+
The result of the lookup
111112
"""
112113
try:
113114
prev_result, expiry, ttl = self._well_known_cache.get_with_expiry(
@@ -124,7 +125,9 @@ def get_well_known(self, server_name):
124125
# requests for the same server in parallel?
125126
try:
126127
with Measure(self._clock, "get_well_known"):
127-
result, cache_period = yield self._fetch_well_known(server_name)
128+
result, cache_period = await self._fetch_well_known(
129+
server_name
130+
) # type: Tuple[Optional[bytes], float]
128131

129132
except _FetchWellKnownFailure as e:
130133
if prev_result and e.temporary:
@@ -153,26 +156,25 @@ def get_well_known(self, server_name):
153156

154157
return WellKnownLookupResult(delegated_server=result)
155158

156-
@defer.inlineCallbacks
157-
def _fetch_well_known(self, server_name):
159+
async def _fetch_well_known(self, server_name: bytes) -> Tuple[bytes, float]:
158160
"""Actually fetch and parse a .well-known, without checking the cache
159161
160162
Args:
161-
server_name (bytes): name of the server, from the requested url
163+
server_name: name of the server, from the requested url
162164
163165
Raises:
164166
_FetchWellKnownFailure if we fail to lookup a result
165167
166168
Returns:
167-
Deferred[Tuple[bytes,int]]: The lookup result and cache period.
169+
The lookup result and cache period.
168170
"""
169171

170172
had_valid_well_known = self._had_valid_well_known_cache.get(server_name, False)
171173

172174
# We do this in two steps to differentiate between possibly transient
173175
# errors (e.g. can't connect to host, 503 response) and more permenant
174176
# errors (such as getting a 404 response).
175-
response, body = yield self._make_well_known_request(
177+
response, body = await self._make_well_known_request(
176178
server_name, retry=had_valid_well_known
177179
)
178180

@@ -215,20 +217,20 @@ def _fetch_well_known(self, server_name):
215217

216218
return result, cache_period
217219

218-
@defer.inlineCallbacks
219-
def _make_well_known_request(self, server_name, retry):
220+
async def _make_well_known_request(
221+
self, server_name: bytes, retry: bool
222+
) -> Tuple[IResponse, bytes]:
220223
"""Make the well known request.
221224
222225
This will retry the request if requested and it fails (with unable
223226
to connect or receives a 5xx error).
224227
225228
Args:
226-
server_name (bytes)
227-
retry (bool): Whether to retry the request if it fails.
229+
server_name: name of the server, from the requested url
230+
retry: Whether to retry the request if it fails.
228231
229232
Returns:
230-
Deferred[tuple[IResponse, bytes]] Returns the response object and
231-
body. Response may be a non-200 response.
233+
Returns the response object and body. Response may be a non-200 response.
232234
"""
233235
uri = b"https://%s/.well-known/matrix/server" % (server_name,)
234236
uri_str = uri.decode("ascii")
@@ -243,12 +245,12 @@ def _make_well_known_request(self, server_name, retry):
243245

244246
logger.info("Fetching %s", uri_str)
245247
try:
246-
response = yield make_deferred_yieldable(
248+
response = await make_deferred_yieldable(
247249
self._well_known_agent.request(
248250
b"GET", uri, headers=Headers(headers)
249251
)
250252
)
251-
body = yield make_deferred_yieldable(readBody(response))
253+
body = await make_deferred_yieldable(readBody(response))
252254

253255
if 500 <= response.code < 600:
254256
raise Exception("Non-200 response %s" % (response.code,))
@@ -265,21 +267,24 @@ def _make_well_known_request(self, server_name, retry):
265267
logger.info("Error fetching %s: %s. Retrying", uri_str, e)
266268

267269
# Sleep briefly in the hopes that they come back up
268-
yield self._clock.sleep(0.5)
270+
await self._clock.sleep(0.5)
269271

270272

271-
def _cache_period_from_headers(headers, time_now=time.time):
273+
def _cache_period_from_headers(
274+
headers: Headers, time_now: Callable[[], float] = time.time
275+
) -> Optional[float]:
272276
cache_controls = _parse_cache_control(headers)
273277

274278
if b"no-store" in cache_controls:
275279
return 0
276280

277281
if b"max-age" in cache_controls:
278-
try:
279-
max_age = int(cache_controls[b"max-age"])
280-
return max_age
281-
except ValueError:
282-
pass
282+
max_age = cache_controls[b"max-age"]
283+
if max_age:
284+
try:
285+
return int(max_age)
286+
except ValueError:
287+
pass
283288

284289
expires = headers.getRawHeaders(b"expires")
285290
if expires is not None:
@@ -295,7 +300,7 @@ def _cache_period_from_headers(headers, time_now=time.time):
295300
return None
296301

297302

298-
def _parse_cache_control(headers):
303+
def _parse_cache_control(headers: Headers) -> Dict[bytes, Optional[bytes]]:
299304
cache_controls = {}
300305
for hdr in headers.getRawHeaders(b"cache-control", []):
301306
for directive in hdr.split(b","):

tests/http/federation/test_matrix_federation_agent.py

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -972,7 +972,9 @@ def test_idna_srv_target(self):
972972
def test_well_known_cache(self):
973973
self.reactor.lookups["testserv"] = "1.2.3.4"
974974

975-
fetch_d = self.well_known_resolver.get_well_known(b"testserv")
975+
fetch_d = defer.ensureDeferred(
976+
self.well_known_resolver.get_well_known(b"testserv")
977+
)
976978

977979
# there should be an attempt to connect on port 443 for the .well-known
978980
clients = self.reactor.tcpClients
@@ -995,15 +997,19 @@ def test_well_known_cache(self):
995997
well_known_server.loseConnection()
996998

997999
# repeat the request: it should hit the cache
998-
fetch_d = self.well_known_resolver.get_well_known(b"testserv")
1000+
fetch_d = defer.ensureDeferred(
1001+
self.well_known_resolver.get_well_known(b"testserv")
1002+
)
9991003
r = self.successResultOf(fetch_d)
10001004
self.assertEqual(r.delegated_server, b"target-server")
10011005

10021006
# expire the cache
10031007
self.reactor.pump((1000.0,))
10041008

10051009
# now it should connect again
1006-
fetch_d = self.well_known_resolver.get_well_known(b"testserv")
1010+
fetch_d = defer.ensureDeferred(
1011+
self.well_known_resolver.get_well_known(b"testserv")
1012+
)
10071013

10081014
self.assertEqual(len(clients), 1)
10091015
(host, port, client_factory, _timeout, _bindAddress) = clients.pop(0)
@@ -1026,7 +1032,9 @@ def test_well_known_cache_with_temp_failure(self):
10261032

10271033
self.reactor.lookups["testserv"] = "1.2.3.4"
10281034

1029-
fetch_d = self.well_known_resolver.get_well_known(b"testserv")
1035+
fetch_d = defer.ensureDeferred(
1036+
self.well_known_resolver.get_well_known(b"testserv")
1037+
)
10301038

10311039
# there should be an attempt to connect on port 443 for the .well-known
10321040
clients = self.reactor.tcpClients
@@ -1052,7 +1060,9 @@ def test_well_known_cache_with_temp_failure(self):
10521060
# another lookup.
10531061
self.reactor.pump((900.0,))
10541062

1055-
fetch_d = self.well_known_resolver.get_well_known(b"testserv")
1063+
fetch_d = defer.ensureDeferred(
1064+
self.well_known_resolver.get_well_known(b"testserv")
1065+
)
10561066

10571067
# The resolver may retry a few times, so fonx all requests that come along
10581068
attempts = 0
@@ -1082,7 +1092,9 @@ def test_well_known_cache_with_temp_failure(self):
10821092
self.reactor.pump((10000.0,))
10831093

10841094
# Repated the request, this time it should fail if the lookup fails.
1085-
fetch_d = self.well_known_resolver.get_well_known(b"testserv")
1095+
fetch_d = defer.ensureDeferred(
1096+
self.well_known_resolver.get_well_known(b"testserv")
1097+
)
10861098

10871099
clients = self.reactor.tcpClients
10881100
(host, port, client_factory, _timeout, _bindAddress) = clients.pop(0)

0 commit comments

Comments
 (0)