Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move rate limiting/retrying to error catching, add tests for rate limit handling #570

Merged
merged 4 commits into from
Jun 1, 2018

Conversation

ggruiz
Copy link
Contributor

@ggruiz ggruiz commented May 31, 2018

Summary

  • Rate limiting/retrying being part of the apiCall()'s .then() area stopped it from actually running, so I moved it to the .catch() portion to make it work.
  • Added relevant tests.

Requirements (place an x in each [ ])

@ggruiz ggruiz requested a review from aoberoi May 31, 2018 01:14
@codecov
Copy link

codecov bot commented May 31, 2018

Codecov Report

Merging #570 into master will increase coverage by 4.14%.
The diff coverage is 90%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master     #570      +/-   ##
==========================================
+ Coverage   81.72%   85.86%   +4.14%     
==========================================
  Files           6        6              
  Lines         279      276       -3     
  Branches       43       42       -1     
==========================================
+ Hits          228      237       +9     
+ Misses         36       27       -9     
+ Partials       15       12       -3
Impacted Files Coverage Δ
src/WebClient.ts 92.3% <90%> (+8.06%) ⬆️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 97e2456...51c0074. Read the comment docs.

it('should expose retry headers in the response', function() {
const scope = nock('https://slack.com')
.post(/api/)
.reply(200, { ok: true }, {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmmm... not quite. we would only ever see retry-after when the response has a status code of 429. i'm not 100% sure what the body would contain, but { ok: true } seems wrong to me, too.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

my bad; i was supposed to change that to 429, but forgot about it. Thanks!

it('should automatically retry the request after the specified timeout', function() {
const scope = nock('https://slack.com')
.post(/api/)
.reply(429, { ok: true }, {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

probably not { ok: true }

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will change this and every instance thereof

const client = new WebClient(token, { retryConfig: { retries: 1 } });
return client.apiCall('method')
.then((resp) => {
assert.propertyVal(resp, 'ok', true);;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how can we verify that the request actually occurred after the specified timeout (1 second)?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

note: time specific, not existence

.post(/api/)
.reply(200, { ok: true });
const client = new WebClient(token, { retryConfig: { retries: 3 } });
return client.apiCall('method')
Copy link
Contributor

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 reflects the intention of the test case. the idea is: given a WebClient with a request concurrency of 2 (just to keep things simple), you fire three requests concurrently (without waiting for the promises to resolve). the first request gets rate-limited, for a specified amount of time, let's say 1 second. the second request would have already been triggered (the concurrency allows for 2 requests to be in flight at the same time) and let's say it completes very quickly (~10ms), but the third request should not even start until after the 1 second timeout from the first request has elapsed. does this make sense?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i get it, will change to reflect this

assert.fail(0, 1, 'Rate Limit retry not turned off');
})
.catch((error) => {
assert.isFalse(scope.isDone());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it makes sense that you're setting up responses that are never meant to trigger in the scope, and therefore you check scope.isDone() rather than calling scope.done(). do you think we should also be cleaning up these test cases in a teardown method with scope.cleanAll()?

src/WebClient.ts Outdated
if (error.statusCode === 429) {
const retryAfterMs = result.retryAfter !== undefined ? result.retryAfter : (60 * 1000);
this.emit('rate_limited', retryAfterMs / 1000);
if (this.retryConfig.retries !== 0) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah-hah. i think you found an issue that actually resides within the tests. the case should allow rate limit triggered retries to be turned off was noted assuming that's functionality we intend to support. but some time after that note, it was made clear that the retryConfig has nothing to do with the rate-limit control built into this object. see: #451

specifically, i think we need to remove this condition and think about that problem more holistically. right now you check a very specific retries property of the retryConfig, but its actually a complex object that's meant to be interpreted by a more sophisticated library like retry. long story short: we need to solve for that test case in a different way, and we should probably remove its implementation for now.

we can start work on resolving #451, but i think that should happen in a separate PR.

accidentally put 'only'

remove overly specific rate limiting functionality, remove tests that need further consideration

remove unnecessary lines
@ggruiz ggruiz merged commit 8d8a115 into slackapi:master Jun 1, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants