Skip to content

Commit

Permalink
Use exponential backoff with jitter on 429
Browse files Browse the repository at this point in the history
This can happen if there are too many clients trying to access the same base.
To accomodate this, use exponential backoff instead of a fixed backoff.
  • Loading branch information
mhahnenberg committed May 3, 2019
1 parent e027f08 commit a572e2c
Show file tree
Hide file tree
Showing 3 changed files with 15 additions and 5 deletions.
2 changes: 1 addition & 1 deletion lib/base.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ var Base = Class.extend({
},

runAction: function(method, path, queryParams, bodyData, callback) {
runAction(this, method, path, queryParams, bodyData, callback);
runAction(this, method, path, queryParams, bodyData, callback, 0);
},

_checkStatusForError: function(statusCode, body) {
Expand Down
3 changes: 2 additions & 1 deletion lib/internal_config.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
{
"RETRY_DELAY_IF_RATE_LIMITED": 5000
"INITIAL_RETRY_DELAY_IF_RATE_LIMITED": 5000,
"MAX_RETRY_DELAY_IF_RATE_LIMITED": 600000
}
15 changes: 12 additions & 3 deletions lib/run_action.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,15 @@ var objectToQueryParamString = require('./object_to_query_param_string');
// This will become require('xhr') in the browser.
var request = require('request');

function runAction(base, method, path, queryParams, bodyData, callback) {
// "Full Jitter" algorithm taken from https://aws.amazon.com/blogs/architecture/exponential-backoff-and-jitter/
function exponentialBackoffWithJitter(numberOfRetries, initialBackoffTimeMs, maxBackoffTimeMs) {
var rawBackoffTimeMs = initialBackoffTimeMs * Math.pow(2, numberOfRetries);
var clippedBackoffTimeMs = Math.min(maxBackoffTimeMs, rawBackoffTimeMs);
var jitteredBackoffTimeMs = Math.random() * clippedBackoffTimeMs;
return jitteredBackoffTimeMs;
}

function runAction(base, method, path, queryParams, bodyData, callback, numAttempts) {
var url = base._airtable._endpointUrl + '/v' + base._airtable._apiVersionMajor + '/' + base._id + path + '?' + objectToQueryParamString(queryParams);

var headers = {
Expand Down Expand Up @@ -49,9 +57,10 @@ function runAction(base, method, path, queryParams, bodyData, callback) {
}

if (resp.statusCode === 429 && !base._airtable._noRetryIfRateLimited) {
var backoffDelayMs = exponentialBackoffWithJitter(numAttempts, internalConfig.INITIAL_RETRY_DELAY_IF_RATE_LIMITED, internalConfig.MAX_RETRY_DELAY_IF_RATE_LIMITED);
setTimeout(function() {
runAction(base, method, path, queryParams, bodyData, callback);
}, internalConfig.RETRY_DELAY_IF_RATE_LIMITED);
runAction(base, method, path, queryParams, bodyData, callback, numAttempts + 1);
}, backoffDelayMs);
return;
}

Expand Down

0 comments on commit a572e2c

Please sign in to comment.