-
-
Notifications
You must be signed in to change notification settings - Fork 2.1k
Remove trailing slashes from outbound federation requests #4840
Conversation
Codecov Report
@@ Coverage Diff @@
## develop #4840 +/- ##
===========================================
+ Coverage 75.34% 75.99% +0.64%
===========================================
Files 340 327 -13
Lines 34924 36941 +2017
Branches 5718 6485 +767
===========================================
+ Hits 26315 28072 +1757
- Misses 6996 7083 +87
- Partials 1613 1786 +173 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah. The main problem here is that these endpoints don't actually return a 404 on synapse 0.99.2 if you hit them without a trailing slash. Empirically, they seem to return a 400 with { "errcode": "M_UNRECOGNIZED" }
, which is something you could check for -- though I urge you to check that each endpoint actually does that before taking my word for it (again).
@@ -473,7 +479,8 @@ def put_json(self, destination, path, args={}, data={}, | |||
json_data_callback=None, | |||
long_retries=False, timeout=None, | |||
ignore_backoff=False, | |||
backoff_on_404=False): | |||
backoff_on_404=False, | |||
try_trailing_slash_on_404=False): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
try_trailing_slash_on_404=False): | |
try_trailing_slash_on_404=False, | |
): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
flake unfortunately complains about visual indentations if we do this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
/me shakes fist
@@ -212,6 +213,11 @@ def _send_request( | |||
|
|||
backoff_on_404 (bool): Back off if we get a 404 | |||
|
|||
try_trailing_slash_on_404 (bool): True if on a 404 response we |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it might be worth adding a note on why this is a useful thing to do ("workaround for #3622 in Synapse 0.99.2 and earlier" ?)
@richvdh Hrm, they seem to all do it. I've left in the check for 404 as well just in case this is new behaviour. |
Use 400 method as well as 404. Lint change did not make flake happy.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
honestly I would be inclined not to do this on 404s. I am like 99% sure that no version of synapse will return a 404, and trying to support 404s in this way complicates things somewhat.
(of course, that also means renaming the options and fixing the comments/docstrings)
# Re-enable backoff if enabled | ||
send_request_args["backoff_on_404"] = backoff_on_404 | ||
|
||
response = yield self.get_json(**send_request_args) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why do we switch to get_json
here?
# or if a 400 with "M_UNRECOGNIZED" which some endpoints return | ||
if (try_trailing_slash_on_404 and | ||
(response.code == 404 | ||
or (response.code == 400 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You've tested this, have you?
|
||
# If enabled, retry with a trailing slash if we received a 404 | ||
if try_trailing_slash_on_404 and response.code == 404: | ||
args["path"] += "/" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
are you sure this is the right thing to do?
response = yield self._send_request(**send_request_args) | ||
|
||
# If enabled, retry with a trailing slash if we received a 404 | ||
if try_trailing_slash_on_404 and response.code == 404: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you seem to have missed the 400 case here, which brings me to:
how about implementing this with a wrapper which you can use in both cases?
def _send_request_with_optional_trailing_slash(request, try_trailing_slash_on_404=False, **kwargs):
self._send_request(request, **kwargs)
if that_worked:
return
fiddle_with(request)
self._send_request(request, **kwargs)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it's coming together, I still has suggestions though!
request, | ||
try_trailing_slash_on_400=False, | ||
backoff_on_404=False, | ||
send_request_args={}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd suggest making this a **kwargs
so that you don't need to build a dict in the calling code.
try_trailing_slash_on_400 (bool): Whether on receiving a 400 | ||
'M_UNRECOGNIZED' from the server to retry the request with a | ||
trailing slash appended to the request path. | ||
404_backoff (bool): Whether to backoff on 404 when making a |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it's not called that
'M_UNRECOGNIZED' from the server to retry the request with a | ||
trailing slash appended to the request path. | ||
404_backoff (bool): Whether to backoff on 404 when making a | ||
request with a trailing slash (only affects request if |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why do we only do this on the retry? surely it is just as applicable for the first one?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mm, good point. When we originally thought we were going to get a 404 on missing a trailing slash rather than a 400, it made sense to not backoff forever before trying again with a trailing slash.
Now there's no need not to do it for best, which consequently also mades the code simpler.
if not try_trailing_slash_on_400: | ||
# Received an error >= 300. Raise unless we're retrying | ||
raise e | ||
except Exception as e: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is a no-op
except HttpResponseException as e: | ||
if not try_trailing_slash_on_400: | ||
# Received an error >= 300. Raise unless we're retrying | ||
raise e |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
raise e | |
raise |
response = yield self._send_request(**send_request_args) | ||
|
||
# Check if it's necessary to retry with a trailing slash | ||
body = yield _handle_json_response( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this (or the other instance need to be in here). The exception, if it happens, will get thrown by _send_request
. Suggest having _send_request_with_optional_trailing_slash
return the response
, and leaving the calls to _handle_json_response
where they were.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It will be necessary if we're checking the body for M_UNRECOGNIZED
, which we need to do again anyways.
try: | ||
response = yield self._send_request(**send_request_args) | ||
|
||
# Check if it's necessary to retry with a trailing slash |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure what this comment means
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can you clean up backoff_on_404?
self, | ||
request, | ||
try_trailing_slash_on_400=False, | ||
backoff_on_404=False, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think there's any need for this now. You can elide it and just let send_request_args
pick it up.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(if there are things that rely on passing it as a positional, rather than keyword, arg, then add a *args
or, better, fix the callers to use the arg name)
@@ -519,17 +578,15 @@ def put_json(self, destination, path, args={}, data={}, | |||
json=data, | |||
) | |||
|
|||
response = yield self._send_request( | |||
request, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: it's probably best to leave it as one arg on each line - it gets a bit impenetrable otherwise.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lgtm!
ftr I don't think the backoff is working correctly here, but not enough to warrant a new issue. I'm seeing a stead 2.5Hz of requests without a trailing slash, and because I haven't updated yet it means that's 2.5Hz of failing requests. |
we didn't implement a backoff... |
Client portion of #4793 and second portion of a solution towards #3622
TODO: