Skip to content
This repository has been archived by the owner on Jun 8, 2022. It is now read-only.

Commit

Permalink
Fix not_authed when retrying after rate limit
Browse files Browse the repository at this point in the history
Retry a rate limited request was not using the correct headers
and payload.
  • Loading branch information
ovv committed Jan 1, 2018
1 parent efb1118 commit bf8ed65
Show file tree
Hide file tree
Showing 6 changed files with 67 additions and 19 deletions.
17 changes: 9 additions & 8 deletions slack/io/abc.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,21 +42,20 @@ async def _rtm(self, url):
async def sleep(self, seconds):
pass

async def _make_query(self, url, data=None, headers=None):
async def _make_query(self, url, body, headers):

while self.rate_limited and self.rate_limited > int(time.time()):
await self.sleep(self.rate_limited - int(time.time()))

status, rep_body, rep_headers = await self._request('POST', url, headers, body)

try:
url, body, headers = sansio.prepare_request(url=url, data=data, headers=headers,
global_headers=self._headers, token=self._token)
status, body, headers = await self._request('POST', url, headers, body)
response_data = sansio.decode_response(status, headers, body)
response_data = sansio.decode_response(status, rep_headers, rep_body)
except exceptions.RateLimited as rate_limited:
if self._retry_when_rate_limit:
LOG.warning('Rate limited ! Waiting for %s seconds', rate_limited.retry_after)
self.rate_limited = int(time.time()) + rate_limited.retry_after
return await self._make_query(url, data, headers)
return await self._make_query(url, body, headers)
else:
raise
else:
Expand All @@ -77,7 +76,9 @@ async def query(self, url, data=None, headers=None):
"""

return await self._make_query(url, data, headers)
url, body, headers = sansio.prepare_request(url=url, data=data, headers=headers,
global_headers=self._headers, token=self._token)
return await self._make_query(url, body, headers)

async def iter(self, url, data=None, headers=None, *, limit=200, iterkey=None, itermode=None):
"""
Expand All @@ -103,7 +104,7 @@ async def iter(self, url, data=None, headers=None, *, limit=200, iterkey=None, i
while True:
data, iterkey, itermode = sansio.prepare_iter_request(url, data, iterkey=iterkey, itermode=itermode,
limit=limit, itervalue=itervalue)
response_data = await self._make_query(url, data, headers)
response_data = await self.query(url, data, headers)
itervalue = sansio.decode_iter_request(response_data)
for item in response_data[iterkey]:
yield item
Expand Down
3 changes: 3 additions & 0 deletions slack/io/aiohttp.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@
class SlackAPI(abc.SlackAPI):
"""
`aiohttp` implementation of :class:`slack.io.abc.SlackAPI`
Args:
session: HTTP session
"""
def __init__(self, *, session, **kwargs):
self._session = session
Expand Down
3 changes: 3 additions & 0 deletions slack/io/curio.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
class SlackAPI(abc.SlackAPI):
"""
`asks curio` implementation of :class:`slack.io.abc.SlackAPI`
Args:
session: HTTP session
"""
def __init__(self, *, session, **kwargs):
self._session = session
Expand Down
26 changes: 15 additions & 11 deletions slack/io/requests.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@
class SlackAPI(abc.SlackAPI):
"""
`requests` implementation of :class:`slack.io.abc.SlackAPI`
Args:
session: HTTP session
"""

def __init__(self, *, session, **kwargs):
Expand All @@ -36,23 +39,22 @@ def _rtm(self, url):
def sleep(self, seconds):
time.sleep(seconds)

def _make_query(self, url, data=None, headers=None):
def _make_query(self, url, body, headers):

while self.rate_limited and self.rate_limited > int(time.time()):
self.sleep(1)
self.sleep(self.rate_limited - int(time.time()))

status, rep_body, rep_headers = self._request('POST', url, headers, body)

try:
url, body, headers = sansio.prepare_request(url=url, data=data, headers=headers,
global_headers=self._headers, token=self._token)
status, body, headers = self._request('POST', url, headers, body)
response_data = sansio.decode_response(status, headers, body)
response_data = sansio.decode_response(status, rep_headers, rep_body)
except exceptions.RateLimited as rate_limited:
if self._retry_when_rate_limit:
raise
else:
LOG.warning('Rate limited ! Waiting for %s seconds', rate_limited.retry_after)
self.rate_limited = int(time.time()) + rate_limited.retry_after
return self._make_query(url, data, headers)
return self._make_query(url, body, headers)
else:
raise
else:
self.rate_limited = False
return response_data
Expand All @@ -70,7 +72,9 @@ def query(self, url, data=None, headers=None):
dictionary of slack API response data
"""
return self._make_query(url, data, headers)
url, body, headers = sansio.prepare_request(url=url, data=data, headers=headers,
global_headers=self._headers, token=self._token)
return self._make_query(url, body, headers)

def iter(self, url, data=None, headers=None, *, limit=200, iterkey=None, itermode=None):
"""
Expand All @@ -96,7 +100,7 @@ def iter(self, url, data=None, headers=None, *, limit=200, iterkey=None, itermod
while True:
data, iterkey, itermode = sansio.prepare_iter_request(url, data, iterkey=iterkey, itermode=itermode,
limit=limit, itervalue=itervalue)
response_data = self._make_query(url, data, headers)
response_data = self.query(url, data, headers)
itervalue = sansio.decode_iter_request(response_data)
for item in response_data[iterkey]:
yield item
Expand Down
3 changes: 3 additions & 0 deletions slack/io/trio.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
class SlackAPI(abc.SlackAPI):
"""
`asks curio` implementation of :class:`slack.io.abc.SlackAPI`
Args:
session: HTTP session
"""
def __init__(self, *, session, **kwargs):
self._session = session
Expand Down
34 changes: 34 additions & 0 deletions tests/test_io.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,40 @@ async def test_retry_rate_limited(self, client):
await client.query(methods.AUTH_TEST)
assert client._request.call_count == 2
client.sleep.assert_called_once_with(1)
assert client._request.call_args_list[0] == client._request.call_args_list[1]
args, kwargs = client._request.call_args_list[0]
assert args == ('POST', 'https://slack.com/api/auth.test', {}, {'token': 'abcdefg'})
assert kwargs == {}

@pytest.mark.parametrize('client', ({'retry_when_rate_limit': True,
'_request': [
{'status': 429, 'body': {"ok": False}, 'headers': {'Retry-After': 1}},
{},
]}, ), indirect=True)
async def test_retry_rate_limited_with_body(self, client):
client.sleep = asynctest.CoroutineMock(side_effect=client.sleep)
await client.query(methods.AUTH_TEST, data={'foo': 'bar'})
assert client._request.call_count == 2
client.sleep.assert_called_once_with(1)
assert client._request.call_args_list[0] == client._request.call_args_list[1]
args, kwargs = client._request.call_args_list[0]
assert args == ('POST', 'https://slack.com/api/auth.test', {}, {'foo': 'bar', 'token': 'abcdefg'})
assert kwargs == {}

@pytest.mark.parametrize('client', ({'retry_when_rate_limit': True,
'_request': [
{'status': 429, 'body': {"ok": False}, 'headers': {'Retry-After': 1}},
{},
]}, ), indirect=True)
async def test_retry_rate_limited_with_headers(self, client):
client.sleep = asynctest.CoroutineMock(side_effect=client.sleep)
await client.query(methods.AUTH_TEST, headers={'foo': 'bar'})
assert client._request.call_count == 2
client.sleep.assert_called_once_with(1)
assert client._request.call_args_list[0] == client._request.call_args_list[1]
args, kwargs = client._request.call_args_list[0]
assert args == ('POST', 'https://slack.com/api/auth.test', {'foo': 'bar'}, {'token': 'abcdefg'})
assert kwargs == {}

@pytest.mark.parametrize('client', ({'retry_when_rate_limit': False,
'_request':
Expand Down

0 comments on commit bf8ed65

Please sign in to comment.