Skip to content

Instantly share code, notes, and snippets.

@blindman2k
Last active August 29, 2015 14:04
Show Gist options
  • Save blindman2k/5f6337ee6d4d378a442a to your computer and use it in GitHub Desktop.
Save blindman2k/5f6337ee6d4d378a442a to your computer and use it in GitHub Desktop.
This HTTPRetry class automatically retries http requests when the agent backend throttles the request with a 429 error. Use it as you would the http object.
HTTPRetry.get("http://icanhazip.com").sendasync(function(res) {
if (res.statuscode == 200) {
server.log(res.body);
} else {
server.log("Error: " + res.statuscode);
}
});
// -----------------------------------------------------------------------------
class HTTPRetry {
function request(method, url, headers = {}, body = "") {
local params = [ method, url, headers, body ];
return HTTPRetryRequest(http.request, params);
}
function get(url, headers = {}) {
local params = [ url, headers ];
return HTTPRetryRequest(http.get, params);
}
function put(url, headers = {}, body = "") {
local params = [ url, headers, body ];
return HTTPRetryRequest(http.put, params);
}
function post(url, headers = {}, body = "") {
local params = [ url, headers, body ];
return HTTPRetryRequest(http.post, params);
}
function httpdelete(url, headers = {}) {
local params = [ url, headers ];
return HTTPRetryRequest(http.httpdelete, params);
}
}
class HTTPRetryRequest {
_request = null;
_params = null;
_retry = null;
_httprequest = null;
constructor(request, params) {
_request = request;
_params = params;
_params.insert(0, this);
}
function sendsync() {
// Prepare the httprequest object and execute the requested function
local result = _request.bindenv(http).acall(_params).sendsync();
while (result.statuscode == 429 && "x-agent-rate-limited" in result.headers && "retry-after" in result.headers) {
// This is a retryable failure, wait for as long as are told then try again
imp.sleep(result.headers["retry-after"].tofloat());
result = _request.bindenv(http).acall(_params).sendsync();
}
return result;
}
function sendasync(oncomplete, longpolldata = null, longpolltimeout = 600) {
// Prepare the httprequest object
_httprequest = _request.bindenv(http).acall(_params);
if (longpolldata == null) {
// Handle a non-long-polling request
_httprequest.sendasync(function(result) {
_httprequest = null;
if (result.statuscode == 429 && "x-agent-rate-limited" in result.headers && "retry-after" in result.headers) {
// This is a retryable failure, wait for as long as are told then try again
_retry = imp.wakeup(result.headers["retry-after"].tofloat(), function() {
_retry = null;
sendasync(oncomplete);
}.bindenv(this));
} else {
oncomplete(result);
}
}.bindenv(this));
} else {
// Handle a long-polling request
_httprequest.sendasync(function(result) {
_httprequest = null;
if (result.statuscode == 429 && "x-agent-rate-limited" in result.headers && "retry-after" in result.headers) {
// This is a retryable failure, wait for as long as are told then try again
_retry = imp.wakeup(result.headers["retry-after"].tofloat(), function() {
_retry = null;
sendasync(oncomplete, longpolldata, longpolltimeout);
}.bindenv(this));
} else {
oncomplete(result);
}
}.bindenv(this), longpolldata, longpolltimeout);
}
return _httprequest;
}
function cancel() {
if (_retry) {
// Cancel the retry timer
imp.cancelwakeup(_retry);
_retry = null;
} else if (_httprequest) {
// Cancel the http request
_httprequest.cancel();
_httprequest = null;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment