Skip to content

Commit

Permalink
KeyError: "X-RateLimit-FillRate" fix (#1593)
Browse files Browse the repository at this point in the history
Co-authored-by: i.myakotin <i.myakotin@tinkoff.ru>
  • Loading branch information
rehsals and i.myakotin committed Feb 7, 2023
1 parent f7d8962 commit 7f91207
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 10 deletions.
36 changes: 26 additions & 10 deletions jira/resilientsession.py
Original file line number Diff line number Diff line change
Expand Up @@ -300,23 +300,39 @@ def __recoverable(
if isinstance(response, Response):
if response.status_code in [429]:
is_recoverable = True
number_of_tokens_issued_per_interval = response.headers[
number_of_tokens_issued_per_interval = response.headers.get(
"X-RateLimit-FillRate"
]
token_issuing_rate_interval_seconds = response.headers[
)
token_issuing_rate_interval_seconds = response.headers.get(
"X-RateLimit-Interval-Seconds"
]
maximum_number_of_tokens = response.headers["X-RateLimit-Limit"]
retry_after = response.headers["retry-after"]
)
maximum_number_of_tokens = response.headers.get("X-RateLimit-Limit")
retry_after = response.headers.get("retry-after")
msg = f"{response.status_code} {response.reason}"
LOG.warning(
f"Request rate limited by Jira: request should be retried after {retry_after} seconds.\n"
+ f"{number_of_tokens_issued_per_interval} tokens are issued every {token_issuing_rate_interval_seconds} seconds. "
+ f"You can accumulate up to {maximum_number_of_tokens} tokens.\n"
warning_msg = "Request rate limited by Jira."

warning_msg += (
f" Request should be retried after {retry_after} seconds.\n"
if retry_after is not None
else "\n"
)
if (
number_of_tokens_issued_per_interval is not None
and token_issuing_rate_interval_seconds is not None
):
warning_msg += f"{number_of_tokens_issued_per_interval} tokens are issued every {token_issuing_rate_interval_seconds} seconds.\n"
if maximum_number_of_tokens is not None:
warning_msg += (
f"You can accumulate up to {maximum_number_of_tokens} tokens.\n"
)
warning_msg = (
warning_msg
+ "Consider adding an exemption for the user as explained in: "
+ "https://confluence.atlassian.com/adminjiraserver/improving-instance-stability-with-rate-limiting-983794911.html"
)

LOG.warning(warning_msg)

if is_recoverable:
# Exponential backoff with full jitter.
delay = min(self.max_retry_delay, 10 * 2**counter) * random.random()
Expand Down
25 changes: 25 additions & 0 deletions tests/test_resilientsession.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,31 @@ def test_status_codes_retries(
assert mocked_sleep_method.call_count == expected_number_of_sleep_invocations


@patch("requests.Session.request")
@patch(f"{jira.resilientsession.__name__}.time.sleep")
@pytest.mark.parametrize(
"status_code,expected_number_of_retries,expected_number_of_sleep_invocations",
status_codes_retries_test_data,
)
def test_status_codes_retries_no_headers(
mocked_sleep_method: Mock,
mocked_request_method: Mock,
status_code: int,
expected_number_of_retries: int,
expected_number_of_sleep_invocations: int,
):
mocked_response: Response = Response()
mocked_response.status_code = status_code
mocked_request_method.return_value = mocked_response
session: jira.resilientsession.ResilientSession = (
jira.resilientsession.ResilientSession()
)
with pytest.raises(JIRAError):
session.get("mocked_url")
assert mocked_request_method.call_count == expected_number_of_retries
assert mocked_sleep_method.call_count == expected_number_of_sleep_invocations


errors_parsing_test_data = [
(403, {"x-authentication-denied-reason": "err1"}, "", ["err1"]),
(500, {}, "err1", ["err1"]),
Expand Down

0 comments on commit 7f91207

Please sign in to comment.