UNPKG

5.81 kBJavaScriptView Raw
1import { __awaiter, __generator } from "tslib";
2import { isThrottlingError } from "@aws-sdk/service-error-classification";
3var DefaultRateLimiter = (function () {
4 function DefaultRateLimiter(options) {
5 var _a, _b, _c, _d, _e;
6 this.currentCapacity = 0;
7 this.enabled = false;
8 this.lastMaxRate = 0;
9 this.measuredTxRate = 0;
10 this.requestCount = 0;
11 this.lastTimestamp = 0;
12 this.timeWindow = 0;
13 this.beta = (_a = options === null || options === void 0 ? void 0 : options.beta) !== null && _a !== void 0 ? _a : 0.7;
14 this.minCapacity = (_b = options === null || options === void 0 ? void 0 : options.minCapacity) !== null && _b !== void 0 ? _b : 1;
15 this.minFillRate = (_c = options === null || options === void 0 ? void 0 : options.minFillRate) !== null && _c !== void 0 ? _c : 0.5;
16 this.scaleConstant = (_d = options === null || options === void 0 ? void 0 : options.scaleConstant) !== null && _d !== void 0 ? _d : 0.4;
17 this.smooth = (_e = options === null || options === void 0 ? void 0 : options.smooth) !== null && _e !== void 0 ? _e : 0.8;
18 var currentTimeInSeconds = this.getCurrentTimeInSeconds();
19 this.lastThrottleTime = currentTimeInSeconds;
20 this.lastTxRateBucket = Math.floor(this.getCurrentTimeInSeconds());
21 this.fillRate = this.minFillRate;
22 this.maxCapacity = this.minCapacity;
23 }
24 DefaultRateLimiter.prototype.getCurrentTimeInSeconds = function () {
25 return Date.now() / 1000;
26 };
27 DefaultRateLimiter.prototype.getSendToken = function () {
28 return __awaiter(this, void 0, void 0, function () {
29 return __generator(this, function (_a) {
30 return [2, this.acquireTokenBucket(1)];
31 });
32 });
33 };
34 DefaultRateLimiter.prototype.acquireTokenBucket = function (amount) {
35 return __awaiter(this, void 0, void 0, function () {
36 var delay_1;
37 return __generator(this, function (_a) {
38 switch (_a.label) {
39 case 0:
40 if (!this.enabled) {
41 return [2];
42 }
43 this.refillTokenBucket();
44 if (!(amount > this.currentCapacity)) return [3, 2];
45 delay_1 = ((amount - this.currentCapacity) / this.fillRate) * 1000;
46 return [4, new Promise(function (resolve) { return setTimeout(resolve, delay_1); })];
47 case 1:
48 _a.sent();
49 _a.label = 2;
50 case 2:
51 this.currentCapacity = this.currentCapacity - amount;
52 return [2];
53 }
54 });
55 });
56 };
57 DefaultRateLimiter.prototype.refillTokenBucket = function () {
58 var timestamp = this.getCurrentTimeInSeconds();
59 if (!this.lastTimestamp) {
60 this.lastTimestamp = timestamp;
61 return;
62 }
63 var fillAmount = (timestamp - this.lastTimestamp) * this.fillRate;
64 this.currentCapacity = Math.min(this.maxCapacity, this.currentCapacity + fillAmount);
65 this.lastTimestamp = timestamp;
66 };
67 DefaultRateLimiter.prototype.updateClientSendingRate = function (response) {
68 var calculatedRate;
69 this.updateMeasuredRate();
70 if (isThrottlingError(response)) {
71 var rateToUse = !this.enabled ? this.measuredTxRate : Math.min(this.measuredTxRate, this.fillRate);
72 this.lastMaxRate = rateToUse;
73 this.calculateTimeWindow();
74 this.lastThrottleTime = this.getCurrentTimeInSeconds();
75 calculatedRate = this.cubicThrottle(rateToUse);
76 this.enableTokenBucket();
77 }
78 else {
79 this.calculateTimeWindow();
80 calculatedRate = this.cubicSuccess(this.getCurrentTimeInSeconds());
81 }
82 var newRate = Math.min(calculatedRate, 2 * this.measuredTxRate);
83 this.updateTokenBucketRate(newRate);
84 };
85 DefaultRateLimiter.prototype.calculateTimeWindow = function () {
86 this.timeWindow = this.getPrecise(Math.pow((this.lastMaxRate * (1 - this.beta)) / this.scaleConstant, 1 / 3));
87 };
88 DefaultRateLimiter.prototype.cubicThrottle = function (rateToUse) {
89 return this.getPrecise(rateToUse * this.beta);
90 };
91 DefaultRateLimiter.prototype.cubicSuccess = function (timestamp) {
92 return this.getPrecise(this.scaleConstant * Math.pow(timestamp - this.lastThrottleTime - this.timeWindow, 3) + this.lastMaxRate);
93 };
94 DefaultRateLimiter.prototype.enableTokenBucket = function () {
95 this.enabled = true;
96 };
97 DefaultRateLimiter.prototype.updateTokenBucketRate = function (newRate) {
98 this.refillTokenBucket();
99 this.fillRate = Math.max(newRate, this.minFillRate);
100 this.maxCapacity = Math.max(newRate, this.minCapacity);
101 this.currentCapacity = Math.min(this.currentCapacity, this.maxCapacity);
102 };
103 DefaultRateLimiter.prototype.updateMeasuredRate = function () {
104 var t = this.getCurrentTimeInSeconds();
105 var timeBucket = Math.floor(t * 2) / 2;
106 this.requestCount++;
107 if (timeBucket > this.lastTxRateBucket) {
108 var currentRate = this.requestCount / (timeBucket - this.lastTxRateBucket);
109 this.measuredTxRate = this.getPrecise(currentRate * this.smooth + this.measuredTxRate * (1 - this.smooth));
110 this.requestCount = 0;
111 this.lastTxRateBucket = timeBucket;
112 }
113 };
114 DefaultRateLimiter.prototype.getPrecise = function (num) {
115 return parseFloat(num.toFixed(8));
116 };
117 return DefaultRateLimiter;
118}());
119export { DefaultRateLimiter };