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

Improve failover logic for MSC3083 restricted rooms #10447

Merged
merged 5 commits into from
Jul 29, 2021
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog.d/10447.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Update support for [MSC3083](https://github.com/matrix-org/matrix-doc/pull/3083) to consider changes in the MSC around which servers can issue join events.
43 changes: 39 additions & 4 deletions synapse/federation/federation_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
Awaitable,
Callable,
Collection,
Container,
Dict,
Iterable,
List,
Expand Down Expand Up @@ -513,6 +514,7 @@ async def _try_destination_list(
description: str,
destinations: Iterable[str],
callback: Callable[[str], Awaitable[T]],
failover_errcodes: Optional[Container[str]] = None,
failover_on_unknown_endpoint: bool = False,
) -> T:
"""Try an operation on a series of servers, until it succeeds
Expand All @@ -533,6 +535,9 @@ async def _try_destination_list(
next server tried. Normally the stacktrace is logged but this is
suppressed if the exception is an InvalidResponseError.

failover_errcodes: Error codes (specific to this endpoint) which should
cause a failover.
clokep marked this conversation as resolved.
Show resolved Hide resolved

failover_on_unknown_endpoint: if True, we will try other servers if it looks
like a server doesn't support the endpoint. This is typically useful
if the endpoint in question is new or experimental.
Expand All @@ -544,6 +549,9 @@ async def _try_destination_list(
SynapseError if the chosen remote server returns a 300/400 code, or
no servers were reachable.
"""
if failover_errcodes is None:
failover_errcodes = ()

for destination in destinations:
if destination == self.server_name:
continue
Expand All @@ -558,11 +566,17 @@ async def _try_destination_list(
synapse_error = e.to_synapse_error()
failover = False

# Failover on an internal server error, or if the destination
# doesn't implemented the endpoint for some reason.
# Failover should occur:
#
# * On internal server errors.
# * If the destination responds that it cannot complete the request.
# * If the destination doesn't implemented the endpoint for some reason.
if 500 <= e.code < 600:
failover = True

elif e.code == 400 and synapse_error.errcode in failover_errcodes:
failover = True

elif failover_on_unknown_endpoint and self._is_unknown_endpoint(
e, synapse_error
):
Expand Down Expand Up @@ -678,8 +692,20 @@ async def send_request(destination: str) -> Tuple[str, EventBase, RoomVersion]:

return destination, ev, room_version

# MSC3083 defines additional error codes for room joins. Unfortunately
# we do not yet know the room version, assume these will only be returned
# by valid room versions.
failover_errcodes = (
(Codes.UNABLE_AUTHORISE_JOIN, Codes.UNABLE_TO_GRANT_JOIN)
if membership == Membership.JOIN
else None
)

return await self._try_destination_list(
"make_" + membership, destinations, send_request
"make_" + membership,
destinations,
send_request,
failover_errcodes=failover_errcodes,
)

async def send_join(
Expand Down Expand Up @@ -818,7 +844,14 @@ async def _execute(pdu: EventBase) -> None:
origin=destination,
)

# MSC3083 defines additional error codes for room joins.
failover_errcodes = None
if room_version.msc3083_join_rules:
failover_errcodes = (
Codes.UNABLE_AUTHORISE_JOIN,
Codes.UNABLE_TO_GRANT_JOIN,
)

# If the join is being authorised via allow rules, we need to send
# the /send_join back to the same server that was originally used
# with /make_join.
Expand All @@ -827,7 +860,9 @@ async def _execute(pdu: EventBase) -> None:
get_domain_from_id(pdu.content["join_authorised_via_users_server"])
]

return await self._try_destination_list("send_join", destinations, send_request)
return await self._try_destination_list(
"send_join", destinations, send_request, failover_errcodes=failover_errcodes
)

async def _do_send_join(
self, room_version: RoomVersion, destination: str, pdu: EventBase
Expand Down