Add tests for exponentialRetryPolicyTests

This commit is contained in:
Dan Schulte 2018-04-09 15:12:34 -07:00
Родитель 8055d3c285
Коммит d7d68fcee6
18 изменённых файлов: 468 добавлений и 126 удалений

27
dist/lib/httpHeaders.js поставляемый
Просмотреть файл

@ -39,9 +39,20 @@ var HttpHeaders = /** @class */ (function () {
return !header ? undefined : header.value;
};
/**
* Get the headers that are contained in this collection.
* Get the headers that are contained this collection as an object.
*/
HttpHeaders.prototype.headers = function () {
HttpHeaders.prototype.rawHeaders = function () {
var result = {};
for (var headerKey in this._headersMap) {
var header = this._headersMap[headerKey];
result[header.name] = header.value;
}
return result;
};
/**
* Get the headers that are contained in this collection as an array.
*/
HttpHeaders.prototype.headersArray = function () {
var headers = [];
for (var headerKey in this._headersMap) {
headers.push(this._headersMap[headerKey]);
@ -53,7 +64,7 @@ var HttpHeaders = /** @class */ (function () {
*/
HttpHeaders.prototype.headerNames = function () {
var headerNames = [];
var headers = this.headers();
var headers = this.headersArray();
for (var i = 0; i < headers.length; ++i) {
headerNames.push(headers[i].name);
}
@ -64,7 +75,7 @@ var HttpHeaders = /** @class */ (function () {
*/
HttpHeaders.prototype.headerValues = function () {
var headerValues = [];
var headers = this.headers();
var headers = this.headersArray();
for (var i = 0; i < headers.length; ++i) {
headerValues.push(headers[i].value);
}
@ -75,12 +86,18 @@ var HttpHeaders = /** @class */ (function () {
*/
HttpHeaders.prototype.toJson = function () {
var result = {};
var headers = this.headers();
var headers = this.headersArray();
for (var i = 0; i < headers.length; ++i) {
result[headers[i].name] = headers[i].value;
}
return result;
};
/**
* Create a deep clone/copy of this HttpHeaders collection.
*/
HttpHeaders.prototype.clone = function () {
return new HttpHeaders(this.rawHeaders());
};
return HttpHeaders;
}());
exports.HttpHeaders = HttpHeaders;

2
dist/lib/httpHeaders.js.map поставляемый
Просмотреть файл

@ -1 +1 @@
{"version":3,"file":"httpHeaders.js","sourceRoot":"","sources":["../../lib/httpHeaders.ts"],"names":[],"mappings":";AAAA,4DAA4D;AAC5D,+FAA+F;;AAE/F;;GAEG;AACH,sBAAsB,UAAkB;IACpC,OAAO,UAAU,CAAC,WAAW,EAAE,CAAC;AACpC,CAAC;AAsBD;;GAEG;AACH;IAGI,qBAAY,UAA2B;QACnC,IAAI,CAAC,WAAW,GAAG,EAAE,CAAC;QACtB,IAAI,UAAU,EAAE;YACZ,KAAK,IAAM,UAAU,IAAI,UAAU,EAAE;gBACjC,IAAI,CAAC,GAAG,CAAC,UAAU,EAAE,UAAU,CAAC,UAAU,CAAC,CAAC,CAAC;aAChD;SACJ;IACL,CAAC;IAED;;;;;OAKG;IACI,yBAAG,GAAV,UAAW,UAAkB,EAAE,WAA4B;QACvD,IAAI,CAAC,WAAW,CAAC,YAAY,CAAC,UAAU,CAAC,CAAC,GAAG,EAAE,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,WAAW,CAAC,QAAQ,EAAE,EAAE,CAAC;IACrG,CAAC;IAED;;;;OAIG;IACI,yBAAG,GAAV,UAAW,UAAkB;QACzB,IAAM,MAAM,GAAe,IAAI,CAAC,WAAW,CAAC,YAAY,CAAC,UAAU,CAAC,CAAC,CAAC;QACtE,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC;IAC9C,CAAC;IAED;;OAEG;IACI,6BAAO,GAAd;QACI,IAAM,OAAO,GAAiB,EAAE,CAAC;QACjC,KAAK,IAAM,SAAS,IAAI,IAAI,CAAC,WAAW,EAAE;YACtC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC,CAAC;SAC7C;QACD,OAAO,OAAO,CAAC;IACnB,CAAC;IAED;;OAEG;IACI,iCAAW,GAAlB;QACI,IAAM,WAAW,GAAa,EAAE,CAAC;QACjC,IAAM,OAAO,GAAiB,IAAI,CAAC,OAAO,EAAE,CAAC;QAC7C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,EAAE;YACrC,WAAW,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;SACrC;QACD,OAAO,WAAW,CAAC;IACvB,CAAC;IAED;;OAEG;IACI,kCAAY,GAAnB;QACI,IAAM,YAAY,GAAa,EAAE,CAAC;QAClC,IAAM,OAAO,GAAiB,IAAI,CAAC,OAAO,EAAE,CAAC;QAC7C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,EAAE;YACrC,YAAY,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;SACvC;QACD,OAAO,YAAY,CAAC;IACxB,CAAC;IAED;;OAEG;IACI,4BAAM,GAAb;QACI,IAAM,MAAM,GAAmB,EAAE,CAAC;QAElC,IAAM,OAAO,GAAiB,IAAI,CAAC,OAAO,EAAE,CAAC;QAC7C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,EAAE;YACrC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;SAC9C;QAED,OAAO,MAAM,CAAC;IAClB,CAAC;IACL,kBAAC;AAAD,CAAC,AAhFD,IAgFC;AAhFY,kCAAW"}
{"version":3,"file":"httpHeaders.js","sourceRoot":"","sources":["../../lib/httpHeaders.ts"],"names":[],"mappings":"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"}

63
dist/lib/httpRequest.js поставляемый
Просмотреть файл

@ -7,61 +7,28 @@ var httpHeaders_1 = require("./httpHeaders");
* An individual HTTP request that can be sent with a HttpClient.
*/
var HttpRequest = /** @class */ (function () {
function HttpRequest(_httpMethod, _url, headers, _body) {
this._httpMethod = _httpMethod;
this._url = _url;
this._body = _body;
if (!this._url) {
var urlString = (this._url === undefined || this._url === null ? this._url : "\"" + this._url + "\"");
/**
*
* @param httpMethod The HTTP method that this request will use.
* @param url The URL that this request will be sent to.
* @param headers The HTTP headers that will be sent with this request.
* @param body The body that will be sent with this request.
*/
function HttpRequest(httpMethod, url, headers, body) {
this.httpMethod = httpMethod;
this.url = url;
this.body = body;
if (!this.url) {
var urlString = (this.url === undefined || this.url === null ? this.url : "\"" + this.url + "\"");
throw new Error(urlString + " is not a valid URL for a HttpRequest.");
}
this._headers = (headers instanceof httpHeaders_1.HttpHeaders ? headers : new httpHeaders_1.HttpHeaders(headers));
this.headers = (headers instanceof httpHeaders_1.HttpHeaders ? headers : new httpHeaders_1.HttpHeaders(headers));
}
Object.defineProperty(HttpRequest.prototype, "httpMethod", {
/**
* Get the HTTP method that this request will use.
*/
get: function () {
return this._httpMethod;
},
enumerable: true,
configurable: true
});
Object.defineProperty(HttpRequest.prototype, "url", {
/**
* Get the URL that this request will be sent to.
*/
get: function () {
return this._url;
},
enumerable: true,
configurable: true
});
Object.defineProperty(HttpRequest.prototype, "headers", {
/**
* Get the HTTP headers that will be sent with this request.
*/
get: function () {
return this._headers;
},
enumerable: true,
configurable: true
});
Object.defineProperty(HttpRequest.prototype, "body", {
/**
* Get the body that will be sent with this request.
*/
get: function () {
return this._body;
},
enumerable: true,
configurable: true
});
/**
* Create a deep clone/copy of this HttpRequest.
*/
HttpRequest.prototype.clone = function () {
return JSON.parse(JSON.stringify(this));
return new HttpRequest(this.httpMethod, this.url, this.headers.clone(), this.body);
};
return HttpRequest;
}());

2
dist/lib/httpRequest.js.map поставляемый
Просмотреть файл

@ -1 +1 @@
{"version":3,"file":"httpRequest.js","sourceRoot":"","sources":["../../lib/httpRequest.ts"],"names":[],"mappings":";;AAAA,4DAA4D;AAC5D,+FAA+F;AAC/F,6CAA4D;AAG5D;;GAEG;AACH;IAGI,qBAAoB,WAAuB,EAAU,IAAY,EAAE,OAAqC,EAAU,KAAc;QAA5G,gBAAW,GAAX,WAAW,CAAY;QAAU,SAAI,GAAJ,IAAI,CAAQ;QAAiD,UAAK,GAAL,KAAK,CAAS;QAC5H,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE;YACZ,IAAM,SAAS,GAAW,CAAC,IAAI,CAAC,IAAI,KAAK,SAAS,IAAI,IAAI,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,OAAI,IAAI,CAAC,IAAI,OAAG,CAAC,CAAC;YACzG,MAAM,IAAI,KAAK,CAAI,SAAS,2CAAwC,CAAC,CAAC;SACzE;QAED,IAAI,CAAC,QAAQ,GAAG,CAAC,OAAO,YAAY,yBAAW,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,yBAAW,CAAC,OAAO,CAAC,CAAC,CAAC;IAC1F,CAAC;IAKD,sBAAW,mCAAU;QAHrB;;WAEG;aACH;YACI,OAAO,IAAI,CAAC,WAAW,CAAC;QAC5B,CAAC;;;OAAA;IAKD,sBAAW,4BAAG;QAHd;;WAEG;aACH;YACI,OAAO,IAAI,CAAC,IAAI,CAAC;QACrB,CAAC;;;OAAA;IAKD,sBAAW,gCAAO;QAHlB;;WAEG;aACH;YACI,OAAO,IAAI,CAAC,QAAQ,CAAC;QACzB,CAAC;;;OAAA;IAKD,sBAAW,6BAAI;QAHf;;WAEG;aACH;YACI,OAAO,IAAI,CAAC,KAAK,CAAC;QACtB,CAAC;;;OAAA;IAED;;OAEG;IACI,2BAAK,GAAZ;QACI,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC;IAC5C,CAAC;IACL,kBAAC;AAAD,CAAC,AA9CD,IA8CC;AA9CY,kCAAW"}
{"version":3,"file":"httpRequest.js","sourceRoot":"","sources":["../../lib/httpRequest.ts"],"names":[],"mappings":";;AAAA,4DAA4D;AAC5D,+FAA+F;AAC/F,6CAA4D;AAG5D;;GAEG;AACH;IAMI;;;;;;OAMG;IACH,qBAAmB,UAAsB,EAAS,GAAW,EAAE,OAAqC,EAAS,IAAa;QAAvG,eAAU,GAAV,UAAU,CAAY;QAAS,QAAG,GAAH,GAAG,CAAQ;QAAgD,SAAI,GAAJ,IAAI,CAAS;QACtH,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE;YACX,IAAM,SAAS,GAAW,CAAC,IAAI,CAAC,GAAG,KAAK,SAAS,IAAI,IAAI,CAAC,GAAG,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,OAAI,IAAI,CAAC,GAAG,OAAG,CAAC,CAAC;YACrG,MAAM,IAAI,KAAK,CAAI,SAAS,2CAAwC,CAAC,CAAC;SACzE;QAED,IAAI,CAAC,OAAO,GAAG,CAAC,OAAO,YAAY,yBAAW,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,yBAAW,CAAC,OAAO,CAAC,CAAC,CAAC;IACzF,CAAC;IAED;;OAEG;IACI,2BAAK,GAAZ;QACI,OAAO,IAAI,WAAW,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;IACvF,CAAC;IACL,kBAAC;AAAD,CAAC,AA5BD,IA4BC;AA5BY,kCAAW"}

124
dist/lib/policies/exponentialRetryPolicy.js поставляемый Normal file
Просмотреть файл

@ -0,0 +1,124 @@
"use strict";
var __extends = (this && this.__extends) || (function () {
var extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
return function (d, b) {
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __generator = (this && this.__generator) || function (thisArg, body) {
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (_) try {
if (f = 1, y && (t = y[op[0] & 2 ? "return" : op[0] ? "throw" : "next"]) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [0, t.value];
switch (op[0]) {
case 0: case 1: t = op; break;
case 4: _.label++; return { value: op[1], done: false };
case 5: _.label++; y = op[1]; op = [0]; continue;
case 7: op = _.ops.pop(); _.trys.pop(); continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
if (t[2]) _.ops.pop();
_.trys.pop(); continue;
}
op = body.call(thisArg, _);
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
}
};
Object.defineProperty(exports, "__esModule", { value: true });
var requestPolicy_1 = require("../requestPolicy");
var utils = require("../util/utils");
/**
* Get a RequestPolicyFactory that creates ExponentialRetryPolicies.
*/
function exponentialRetryPolicy(retryOptions) {
return function (nextPolicy, options) {
return new ExponentialRetryPolicy(retryOptions || {}, nextPolicy, options);
};
}
exports.exponentialRetryPolicy = exponentialRetryPolicy;
var ExponentialRetryPolicy = /** @class */ (function (_super) {
__extends(ExponentialRetryPolicy, _super);
function ExponentialRetryPolicy(retryOptions, nextPolicy, options) {
var _this = _super.call(this, nextPolicy, options) || this;
_this._maximumAttempts = retryOptions.maximumAttempts || 3;
_this._initialRetryDelayInMilliseconds = retryOptions.initialRetryDelayInMilliseconds || 30 * 1000;
_this._maximumRetryDelayInMilliseconds = retryOptions.maximumRetryIntervalInMilliseconds || 90 * 1000;
_this._delayFunction = retryOptions.delayFunction || utils.delay;
return _this;
}
ExponentialRetryPolicy.prototype.send = function (request) {
return __awaiter(this, void 0, void 0, function () {
var response, shouldAttempt, attemptNumber, attemptDelayInMilliseconds, responseError, statusCode, error_1, boundedRandomDelta, incrementDelta;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
shouldAttempt = true;
attemptNumber = 0;
attemptDelayInMilliseconds = this._initialRetryDelayInMilliseconds;
_a.label = 1;
case 1:
if (!shouldAttempt) return [3 /*break*/, 8];
_a.label = 2;
case 2:
_a.trys.push([2, 4, , 5]);
++attemptNumber;
return [4 /*yield*/, this._nextPolicy.send(request.clone())];
case 3:
response = _a.sent();
if (response) {
statusCode = response.statusCode;
if ((statusCode < 500 && statusCode !== 408) || statusCode === 501 || statusCode === 505) {
shouldAttempt = false;
responseError = undefined;
}
}
return [3 /*break*/, 5];
case 4:
error_1 = _a.sent();
if (responseError) {
error_1.innerError = responseError;
}
responseError = error_1;
return [3 /*break*/, 5];
case 5:
shouldAttempt = shouldAttempt && attemptNumber < this._maximumAttempts;
if (!shouldAttempt) return [3 /*break*/, 7];
response = undefined;
if (attemptNumber >= 2) {
boundedRandomDelta = (attemptDelayInMilliseconds * 0.8) + Math.floor(Math.random() * attemptDelayInMilliseconds * 0.4);
incrementDelta = (Math.pow(2, attemptNumber) - 1) * boundedRandomDelta;
attemptDelayInMilliseconds = Math.min(attemptDelayInMilliseconds + incrementDelta, this._maximumRetryDelayInMilliseconds);
}
return [4 /*yield*/, this._delayFunction(attemptDelayInMilliseconds)];
case 6:
_a.sent();
_a.label = 7;
case 7: return [3 /*break*/, 1];
case 8: return [2 /*return*/, response ? Promise.resolve(response) : Promise.reject(responseError)];
}
});
});
};
return ExponentialRetryPolicy;
}(requestPolicy_1.BaseRequestPolicy));
//# sourceMappingURL=exponentialRetryPolicy.js.map

1
dist/lib/policies/exponentialRetryPolicy.js.map поставляемый Normal file
Просмотреть файл

@ -0,0 +1 @@
{"version":3,"file":"exponentialRetryPolicy.js","sourceRoot":"","sources":["../../../lib/policies/exponentialRetryPolicy.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAIA,kDAAoE;AAGpE,qCAAuC;AA2CvC;;GAEG;AACH,gCAAuC,YAA2B;IAC9D,OAAO,UAAC,UAAyB,EAAE,OAA6B;QAC5D,OAAO,IAAI,sBAAsB,CAAC,YAAY,IAAI,EAAE,EAAE,UAAU,EAAE,OAAO,CAAC,CAAC;IAC/E,CAAC,CAAC;AACN,CAAC;AAJD,wDAIC;AAED;IAAqC,0CAAiB;IAMlD,gCAAY,YAA0B,EAAE,UAAyB,EAAE,OAA6B;QAAhG,YACI,kBAAM,UAAU,EAAE,OAAO,CAAC,SAM7B;QAJG,KAAI,CAAC,gBAAgB,GAAG,YAAY,CAAC,eAAe,IAAI,CAAC,CAAC;QAC1D,KAAI,CAAC,gCAAgC,GAAG,YAAY,CAAC,+BAA+B,IAAI,EAAE,GAAG,IAAI,CAAC;QAClG,KAAI,CAAC,gCAAgC,GAAG,YAAY,CAAC,kCAAkC,IAAI,EAAE,GAAG,IAAI,CAAC;QACrG,KAAI,CAAC,cAAc,GAAG,YAAY,CAAC,aAAa,IAAI,KAAK,CAAC,KAAK,CAAC;;IACpE,CAAC;IAEY,qCAAI,GAAjB,UAAkB,OAAoB;;;;;;wBAE9B,aAAa,GAAG,IAAI,CAAC;wBACrB,aAAa,GAAG,CAAC,CAAC;wBAClB,0BAA0B,GAAW,IAAI,CAAC,gCAAgC,CAAC;;;6BAExE,aAAa;;;;wBAEZ,EAAE,aAAa,CAAC;wBACL,qBAAM,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC,EAAA;;wBAAvD,QAAQ,GAAG,SAA4C,CAAC;wBAExD,IAAI,QAAQ,EAAE;4BACJ,UAAU,GAAW,QAAQ,CAAC,UAAU,CAAC;4BAC/C,IAAI,CAAC,UAAU,GAAG,GAAG,IAAI,UAAU,KAAK,GAAG,CAAC,IAAI,UAAU,KAAK,GAAG,IAAI,UAAU,KAAK,GAAG,EAAE;gCACtF,aAAa,GAAG,KAAK,CAAC;gCACtB,aAAa,GAAG,SAAS,CAAC;6BAC7B;yBACJ;;;;wBAED,IAAI,aAAa,EAAE;4BACf,OAAK,CAAC,UAAU,GAAG,aAAa,CAAC;yBACpC;wBACD,aAAa,GAAG,OAAK,CAAC;;;wBAG1B,aAAa,GAAG,aAAa,IAAI,aAAa,GAAG,IAAI,CAAC,gBAAgB,CAAC;6BACnE,aAAa,EAAb,wBAAa;wBACb,QAAQ,GAAG,SAAS,CAAC;wBAErB,IAAI,aAAa,IAAI,CAAC,EAAE;4BACd,kBAAkB,GAAW,CAAC,0BAA0B,GAAG,GAAG,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,0BAA0B,GAAG,GAAG,CAAC,CAAC;4BAC/H,cAAc,GAAW,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,aAAa,CAAC,GAAG,CAAC,CAAC,GAAG,kBAAkB,CAAC;4BACrF,0BAA0B,GAAG,IAAI,CAAC,GAAG,CAAC,0BAA0B,GAAG,cAAc,EAAE,IAAI,CAAC,gCAAgC,CAAC,CAAC;yBAC7H;wBAED,qBAAM,IAAI,CAAC,cAAc,CAAC,0BAA0B,CAAC,EAAA;;wBAArD,SAAqD,CAAC;;;4BAG9D,sBAAO,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,aAAa,CAAC,EAAC;;;;KAC/E;IACL,6BAAC;AAAD,CAAC,AAvDD,CAAqC,iCAAiB,GAuDrD"}

2
dist/lib/policies/userAgentPolicy.js поставляемый
Просмотреть файл

@ -15,7 +15,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
var httpPipelineLogLevel_1 = require("../httpPipelineLogLevel");
var requestPolicy_1 = require("../requestPolicy");
/**
* Get a RequestPolicyFactory that creates UserAgentRequestPolicies.
* Get a RequestPolicyFactory that creates UserAgentPolicies.
* @param userAgent The userAgent string to apply to each outgoing request.
*/
function userAgentPolicy(userAgent) {

111
dist/test/policies/exponentialRetryPolicyTests.js поставляемый Normal file
Просмотреть файл

@ -0,0 +1,111 @@
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __generator = (this && this.__generator) || function (thisArg, body) {
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (_) try {
if (f = 1, y && (t = y[op[0] & 2 ? "return" : op[0] ? "throw" : "next"]) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [0, t.value];
switch (op[0]) {
case 0: case 1: t = op; break;
case 4: _.label++; return { value: op[1], done: false };
case 5: _.label++; y = op[1]; op = [0]; continue;
case 7: op = _.ops.pop(); _.trys.pop(); continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
if (t[2]) _.ops.pop();
_.trys.pop(); continue;
}
op = body.call(thisArg, _);
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
}
};
var _this = this;
Object.defineProperty(exports, "__esModule", { value: true });
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.
var assert = require("assert");
var httpMethod_1 = require("../../lib/httpMethod");
var httpRequest_1 = require("../../lib/httpRequest");
var exponentialRetryPolicy_1 = require("../../lib/policies/exponentialRetryPolicy");
var requestPolicyOptions_1 = require("../../lib/requestPolicyOptions");
var inMemoryHttpResponse_1 = require("../inMemoryHttpResponse");
describe("exponentialRetryPolicy", function () {
it("should do nothing if no error occurs", function () { return __awaiter(_this, void 0, void 0, function () {
var policyFactory, nextPolicy, policy, request, response;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
policyFactory = exponentialRetryPolicy_1.exponentialRetryPolicy({
maximumAttempts: 3,
initialRetryDelayInMilliseconds: 100,
maximumRetryIntervalInMilliseconds: 1000
});
nextPolicy = {
send: function (request) {
request.headers.set("A", "B");
return Promise.resolve(new inMemoryHttpResponse_1.InMemoryHttpResponse(request, 200, {}));
}
};
policy = policyFactory(nextPolicy, new requestPolicyOptions_1.RequestPolicyOptions());
request = new httpRequest_1.HttpRequest(httpMethod_1.HttpMethod.GET, "https://spam.com", {});
return [4 /*yield*/, policy.send(request)];
case 1:
response = _a.sent();
assert.deepStrictEqual(request, new httpRequest_1.HttpRequest(httpMethod_1.HttpMethod.GET, "https://spam.com", {}), "The original request should not be modified.");
assert.deepStrictEqual(response.request, new httpRequest_1.HttpRequest(httpMethod_1.HttpMethod.GET, "https://spam.com", { "A": "B" }), "The request associated with the response should have the modified header.");
return [2 /*return*/];
}
});
}); });
it("should retry if an undefined HttpResponse is returned", function () { return __awaiter(_this, void 0, void 0, function () {
var millisecondsDelayed, policyFactory, attempt, nextPolicy, policy, request, response;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
millisecondsDelayed = 0;
policyFactory = exponentialRetryPolicy_1.exponentialRetryPolicy({
maximumAttempts: 3,
initialRetryDelayInMilliseconds: 30 * 1000,
maximumRetryIntervalInMilliseconds: 90 * 1000,
delayFunction: function (delayInMilliseconds) {
millisecondsDelayed += delayInMilliseconds;
return Promise.resolve();
}
});
attempt = 0;
nextPolicy = {
send: function (request) {
++attempt;
request.headers.set("A", attempt);
return Promise.resolve(attempt === 1 ? undefined : new inMemoryHttpResponse_1.InMemoryHttpResponse(request, 200, {}));
}
};
policy = policyFactory(nextPolicy, new requestPolicyOptions_1.RequestPolicyOptions());
request = new httpRequest_1.HttpRequest(httpMethod_1.HttpMethod.GET, "https://spam.com", {});
return [4 /*yield*/, policy.send(request)];
case 1:
response = _a.sent();
assert.deepStrictEqual(request, new httpRequest_1.HttpRequest(httpMethod_1.HttpMethod.GET, "https://spam.com", {}), "The original request should not be modified.");
assert.deepStrictEqual(response.request, new httpRequest_1.HttpRequest(httpMethod_1.HttpMethod.GET, "https://spam.com", { "A": "2" }), "The request associated with the response should have the modified header.");
assert.strictEqual(millisecondsDelayed, 30 * 1000);
return [2 /*return*/];
}
});
}); });
});
//# sourceMappingURL=exponentialRetryPolicyTests.js.map

1
dist/test/policies/exponentialRetryPolicyTests.js.map поставляемый Normal file
Просмотреть файл

@ -0,0 +1 @@
{"version":3,"file":"exponentialRetryPolicyTests.js","sourceRoot":"","sources":["../../../test/policies/exponentialRetryPolicyTests.ts"],"names":[],"mappings":"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"}

Просмотреть файл

@ -64,9 +64,21 @@ export class HttpHeaders {
}
/**
* Get the headers that are contained in this collection.
* Get the headers that are contained this collection as an object.
*/
public headers(): HttpHeader[] {
public rawHeaders(): RawHttpHeaders {
const result: RawHttpHeaders = {};
for (const headerKey in this._headersMap) {
const header: HttpHeader = this._headersMap[headerKey];
result[header.name] = header.value;
}
return result;
}
/**
* Get the headers that are contained in this collection as an array.
*/
public headersArray(): HttpHeader[] {
const headers: HttpHeader[] = [];
for (const headerKey in this._headersMap) {
headers.push(this._headersMap[headerKey]);
@ -79,7 +91,7 @@ export class HttpHeaders {
*/
public headerNames(): string[] {
const headerNames: string[] = [];
const headers: HttpHeader[] = this.headers();
const headers: HttpHeader[] = this.headersArray();
for (let i = 0; i < headers.length; ++i) {
headerNames.push(headers[i].name);
}
@ -91,7 +103,7 @@ export class HttpHeaders {
*/
public headerValues(): string[] {
const headerValues: string[] = [];
const headers: HttpHeader[] = this.headers();
const headers: HttpHeader[] = this.headersArray();
for (let i = 0; i < headers.length; ++i) {
headerValues.push(headers[i].value);
}
@ -104,11 +116,18 @@ export class HttpHeaders {
public toJson(): RawHttpHeaders {
const result: RawHttpHeaders = {};
const headers: HttpHeader[] = this.headers();
const headers: HttpHeader[] = this.headersArray();
for (let i = 0; i < headers.length; ++i) {
result[headers[i].name] = headers[i].value;
}
return result;
}
/**
* Create a deep clone/copy of this HttpHeaders collection.
*/
public clone(): HttpHeaders {
return new HttpHeaders(this.rawHeaders());
}
}

Просмотреть файл

@ -7,49 +7,31 @@ import { HttpMethod } from "./httpMethod";
* An individual HTTP request that can be sent with a HttpClient.
*/
export class HttpRequest {
private readonly _headers: HttpHeaders;
constructor(private _httpMethod: HttpMethod, private _url: string, headers: HttpHeaders | RawHttpHeaders, private _body?: string) {
if (!this._url) {
const urlString: string = (this._url === undefined || this._url === null ? this._url : `"${this._url}"`);
throw new Error(`${urlString} is not a valid URL for a HttpRequest.`);
}
this._headers = (headers instanceof HttpHeaders ? headers : new HttpHeaders(headers));
}
/**
* Get the HTTP method that this request will use.
*/
public get httpMethod(): HttpMethod {
return this._httpMethod;
}
/**
* Get the URL that this request will be sent to.
*/
public get url(): string {
return this._url;
}
/**
* Get the HTTP headers that will be sent with this request.
*/
public get headers(): HttpHeaders {
return this._headers;
}
public readonly headers: HttpHeaders;
/**
* Get the body that will be sent with this request.
*
* @param httpMethod The HTTP method that this request will use.
* @param url The URL that this request will be sent to.
* @param headers The HTTP headers that will be sent with this request.
* @param body The body that will be sent with this request.
*/
public get body(): string | undefined {
return this._body;
constructor(public httpMethod: HttpMethod, public url: string, headers: HttpHeaders | RawHttpHeaders, public body?: string) {
if (!this.url) {
const urlString: string = (this.url === undefined || this.url === null ? this.url : `"${this.url}"`);
throw new Error(`${urlString} is not a valid URL for a HttpRequest.`);
}
this.headers = (headers instanceof HttpHeaders ? headers : new HttpHeaders(headers));
}
/**
* Create a deep clone/copy of this HttpRequest.
*/
public clone(): HttpRequest {
return JSON.parse(JSON.stringify(this));
return new HttpRequest(this.httpMethod, this.url, this.headers.clone(), this.body);
}
}

Просмотреть файл

@ -42,6 +42,10 @@ export interface RetryOptions {
* The maximum number of milliseconds to wait before retrying.
*/
maximumRetryIntervalInMilliseconds?: number;
/**
* The function to use to delay before sending a retry attempt.
*/
delayFunction?: (delayInMilliseconds: number) => Promise<void>;
}
/**
@ -49,33 +53,35 @@ export interface RetryOptions {
*/
export function exponentialRetryPolicy(retryOptions?: RetryOptions): RequestPolicyFactory {
return (nextPolicy: RequestPolicy, options: RequestPolicyOptions) => {
return new ExponentialRetryPolicy(retryOptions || {}, nextPolicy, options, utils.delay);
return new ExponentialRetryPolicy(retryOptions || {}, nextPolicy, options);
};
}
class ExponentialRetryPolicy extends BaseRequestPolicy {
private readonly maximumAttempts: number;
private readonly initialRetryDelayInMilliseconds: number;
private readonly maximumRetryDelayInMilliseconds: number;
private readonly _maximumAttempts: number;
private readonly _initialRetryDelayInMilliseconds: number;
private readonly _maximumRetryDelayInMilliseconds: number;
private readonly _delayFunction: (delayInMilliseconds: number) => Promise<void>;
constructor(retryOptions: RetryOptions, nextPolicy: RequestPolicy, options: RequestPolicyOptions, private readonly delayFunction: (delay: number) => Promise<never>) {
constructor(retryOptions: RetryOptions, nextPolicy: RequestPolicy, options: RequestPolicyOptions) {
super(nextPolicy, options);
this.maximumAttempts = retryOptions.maximumAttempts || 3;
this.initialRetryDelayInMilliseconds = retryOptions.initialRetryDelayInMilliseconds || 30 * 1000;
this.maximumRetryDelayInMilliseconds = retryOptions.maximumRetryIntervalInMilliseconds || 90 * 1000;
this._maximumAttempts = retryOptions.maximumAttempts || 3;
this._initialRetryDelayInMilliseconds = retryOptions.initialRetryDelayInMilliseconds || 30 * 1000;
this._maximumRetryDelayInMilliseconds = retryOptions.maximumRetryIntervalInMilliseconds || 90 * 1000;
this._delayFunction = retryOptions.delayFunction || utils.delay;
}
public async send(request: HttpRequest): Promise<HttpResponse> {
let response: HttpResponse | undefined;
let shouldAttempt: boolean = true;
let attemptNumber: number = 0;
let attemptDelayInMilliseconds: number = this.initialRetryDelayInMilliseconds;
let shouldAttempt = true;
let attemptNumber = 0;
let attemptDelayInMilliseconds: number = this._initialRetryDelayInMilliseconds;
let responseError: RetryError | undefined;
while (shouldAttempt) {
try {
++attemptNumber;
response = await this.nextPolicy.send(request.clone());
response = await this._nextPolicy.send(request.clone());
if (response) {
const statusCode: number = response.statusCode;
@ -91,17 +97,17 @@ class ExponentialRetryPolicy extends BaseRequestPolicy {
responseError = error;
}
shouldAttempt = shouldAttempt && attemptNumber < this.maximumAttempts;
shouldAttempt = shouldAttempt && attemptNumber < this._maximumAttempts;
if (shouldAttempt) {
response = undefined;
if (attemptNumber >= 2) {
const boundedRandomDelta: number = (attemptDelayInMilliseconds * 0.8) + Math.floor(Math.random() * attemptDelayInMilliseconds * 0.4);
const incrementDelta: number = (Math.pow(2, attemptNumber) - 1) * boundedRandomDelta;
attemptDelayInMilliseconds = Math.min(attemptDelayInMilliseconds + incrementDelta, this.maximumRetryDelayInMilliseconds);
attemptDelayInMilliseconds = Math.min(attemptDelayInMilliseconds + incrementDelta, this._maximumRetryDelayInMilliseconds);
}
await this.delayFunction(attemptDelayInMilliseconds);
await this._delayFunction(attemptDelayInMilliseconds);
}
}
return response ? Promise.resolve(response) : Promise.reject(responseError);

Просмотреть файл

@ -0,0 +1,67 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.
import * as assert from "assert";
import { HttpMethod } from "../../lib/httpMethod";
import { HttpRequest } from "../../lib/httpRequest";
import { HttpResponse } from "../../lib/httpResponse";
import { exponentialRetryPolicy } from "../../lib/policies/exponentialRetryPolicy";
import { RequestPolicy } from "../../lib/requestPolicy";
import { RequestPolicyFactory } from "../../lib/requestPolicyFactory";
import { RequestPolicyOptions } from "../../lib/requestPolicyOptions";
import { InMemoryHttpResponse } from "../inMemoryHttpResponse";
describe("exponentialRetryPolicy", () => {
it("should do nothing if no error occurs", async () => {
const policyFactory: RequestPolicyFactory = exponentialRetryPolicy({
maximumAttempts: 3,
initialRetryDelayInMilliseconds: 100,
maximumRetryIntervalInMilliseconds: 1000
});
const nextPolicy: RequestPolicy = {
send: (request: HttpRequest) => {
request.headers.set("A", "B");
return Promise.resolve(new InMemoryHttpResponse(request, 200, {}));
}
}
const policy: RequestPolicy = policyFactory(nextPolicy, new RequestPolicyOptions());
const request = new HttpRequest(HttpMethod.GET, "https://spam.com", {});
const response: HttpResponse = await policy.send(request);
assert.deepStrictEqual(request, new HttpRequest(HttpMethod.GET, "https://spam.com", {}), "The original request should not be modified.");
assert.deepStrictEqual(response.request, new HttpRequest(HttpMethod.GET, "https://spam.com", { "A": "B" }), "The request associated with the response should have the modified header.");
});
it("should retry if an undefined HttpResponse is returned", async () => {
let millisecondsDelayed: number = 0;
const policyFactory: RequestPolicyFactory = exponentialRetryPolicy({
maximumAttempts: 3,
initialRetryDelayInMilliseconds: 30 * 1000,
maximumRetryIntervalInMilliseconds: 90 * 1000,
delayFunction: (delayInMilliseconds: number) => {
millisecondsDelayed += delayInMilliseconds;
return Promise.resolve();
}
});
let attempt = 0;
const nextPolicy: RequestPolicy = {
send: (request: HttpRequest) => {
++attempt;
request.headers.set("A", attempt);
return Promise.resolve(attempt === 1 ? <any>undefined : new InMemoryHttpResponse(request, 200, {}));
}
}
const policy: RequestPolicy = policyFactory(nextPolicy, new RequestPolicyOptions());
const request = new HttpRequest(HttpMethod.GET, "https://spam.com", {});
const response: HttpResponse = await policy.send(request);
assert.deepStrictEqual(request, new HttpRequest(HttpMethod.GET, "https://spam.com", {}), "The original request should not be modified.");
assert.deepStrictEqual(response.request, new HttpRequest(HttpMethod.GET, "https://spam.com", { "A": "2" }), "The request associated with the response should have the modified header.");
assert.strictEqual(millisecondsDelayed, 30 * 1000);
});
});

12
typings/lib/httpHeaders.d.ts поставляемый
Просмотреть файл

@ -37,9 +37,13 @@ export declare class HttpHeaders {
*/
get(headerName: string): string | undefined;
/**
* Get the headers that are contained in this collection.
* Get the headers that are contained this collection as an object.
*/
headers(): HttpHeader[];
rawHeaders(): RawHttpHeaders;
/**
* Get the headers that are contained in this collection as an array.
*/
headersArray(): HttpHeader[];
/**
* Get the header names that are contained in this collection.
*/
@ -52,4 +56,8 @@ export declare class HttpHeaders {
* Get the JSON object representation of this HTTP header collection.
*/
toJson(): RawHttpHeaders;
/**
* Create a deep clone/copy of this HttpHeaders collection.
*/
clone(): HttpHeaders;
}

24
typings/lib/httpRequest.d.ts поставляемый
Просмотреть файл

@ -4,27 +4,21 @@ import { HttpMethod } from "./httpMethod";
* An individual HTTP request that can be sent with a HttpClient.
*/
export declare class HttpRequest {
private _httpMethod;
private _url;
private _body;
private readonly _headers;
constructor(_httpMethod: HttpMethod, _url: string, headers: HttpHeaders | RawHttpHeaders, _body?: string | undefined);
/**
* Get the HTTP method that this request will use.
*/
readonly httpMethod: HttpMethod;
/**
* Get the URL that this request will be sent to.
*/
readonly url: string;
httpMethod: HttpMethod;
url: string;
body: string | undefined;
/**
* Get the HTTP headers that will be sent with this request.
*/
readonly headers: HttpHeaders;
/**
* Get the body that will be sent with this request.
*
* @param httpMethod The HTTP method that this request will use.
* @param url The URL that this request will be sent to.
* @param headers The HTTP headers that will be sent with this request.
* @param body The body that will be sent with this request.
*/
readonly body: string | undefined;
constructor(httpMethod: HttpMethod, url: string, headers: HttpHeaders | RawHttpHeaders, body?: string | undefined);
/**
* Create a deep clone/copy of this HttpRequest.
*/

44
typings/lib/policies/exponentialRetryPolicy.d.ts поставляемый Normal file
Просмотреть файл

@ -0,0 +1,44 @@
import { RequestPolicyFactory } from "../requestPolicyFactory";
/**
* An error that can be thrown when the maximum number of attempts have been attempted.
*/
export interface RetryError extends Error {
/**
* The message that describes the retry failure.
*/
message: string;
/**
* The error code that describes the retry failure.
*/
code?: string;
/**
* An inner error that this RetryError wraps.
*/
innerError?: RetryError;
}
/**
* The options that can be passed to an ExponentialRetryPolicy.
*/
export interface RetryOptions {
/**
* The maximum number of attempts that the retry policy will perform before failing. The first
* attempt after a failure is considered the 2nd attempt.
*/
maximumAttempts?: number;
/**
* The number of milliseconds to delay before attempting again.
*/
initialRetryDelayInMilliseconds?: number;
/**
* The maximum number of milliseconds to wait before retrying.
*/
maximumRetryIntervalInMilliseconds?: number;
/**
* The function to use to delay before sending a retry attempt.
*/
delayFunction?: (delayInMilliseconds: number) => Promise<void>;
}
/**
* Get a RequestPolicyFactory that creates ExponentialRetryPolicies.
*/
export declare function exponentialRetryPolicy(retryOptions?: RetryOptions): RequestPolicyFactory;

2
typings/lib/policies/userAgentPolicy.d.ts поставляемый
Просмотреть файл

@ -1,6 +1,6 @@
import { RequestPolicyFactory } from "../requestPolicyFactory";
/**
* Get a RequestPolicyFactory that creates UserAgentRequestPolicies.
* Get a RequestPolicyFactory that creates UserAgentPolicies.
* @param userAgent The userAgent string to apply to each outgoing request.
*/
export declare function userAgentPolicy(userAgent: string): RequestPolicyFactory;

1
typings/test/policies/exponentialRetryPolicyTests.d.ts поставляемый Normal file
Просмотреть файл

@ -0,0 +1 @@
export {};