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 |
richvdh
left a comment
There was a problem hiding this comment.
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).
| ignore_backoff=False, | ||
| backoff_on_404=False): | ||
| backoff_on_404=False, | ||
| try_trailing_slash_on_404=False): |
There was a problem hiding this comment.
| try_trailing_slash_on_404=False): | |
| try_trailing_slash_on_404=False, | |
| ): |
There was a problem hiding this comment.
flake unfortunately complains about visual indentations if we do this.
|
|
||
| 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.
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.
richvdh
left a comment
There was a problem hiding this comment.
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.
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 |
|
|
||
| # 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.
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.
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)
richvdh
left a comment
There was a problem hiding this comment.
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.
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 |
| '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.
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.
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: |
| except HttpResponseException as e: | ||
| if not try_trailing_slash_on_400: | ||
| # Received an error >= 300. Raise unless we're retrying | ||
| raise e |
| 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.
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.
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.
I'm not sure what this comment means
richvdh
left a comment
There was a problem hiding this comment.
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.
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.
(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)
| ) | ||
|
|
||
| response = yield self._send_request( | ||
| request, |
There was a problem hiding this comment.
nit: it's probably best to leave it as one arg on each line - it gets a bit impenetrable otherwise.
|
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: