@libp2p/utils 5.4.0-1488a7371 → 5.4.0-4ad63bb79
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/src/adaptive-timeout.d.ts +35 -0
- package/dist/src/adaptive-timeout.d.ts.map +1 -0
- package/dist/src/adaptive-timeout.js +63 -0
- package/dist/src/adaptive-timeout.js.map +1 -0
- package/dist/src/moving-average.d.ts +18 -0
- package/dist/src/moving-average.d.ts.map +1 -0
- package/dist/src/moving-average.js +43 -0
- package/dist/src/moving-average.js.map +1 -0
- package/package.json +13 -5
- package/src/adaptive-timeout.ts +94 -0
- package/src/moving-average.ts +45 -0
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { type ClearableSignal } from 'any-signal';
|
|
2
|
+
import type { Metrics } from '@libp2p/interface';
|
|
3
|
+
export declare const DEFAULT_TIMEOUT_MULTIPLIER = 1.2;
|
|
4
|
+
export declare const DEFAULT_FAILURE_MULTIPLIER = 2;
|
|
5
|
+
export declare const DEFAULT_MIN_TIMEOUT = 2000;
|
|
6
|
+
export interface AdaptiveTimeoutSignal extends ClearableSignal {
|
|
7
|
+
start: number;
|
|
8
|
+
timeout: number;
|
|
9
|
+
}
|
|
10
|
+
export interface AdaptiveTimeoutInit {
|
|
11
|
+
metricName?: string;
|
|
12
|
+
metrics?: Metrics;
|
|
13
|
+
interval?: number;
|
|
14
|
+
initialValue?: number;
|
|
15
|
+
timeoutMultiplier?: number;
|
|
16
|
+
failureMultiplier?: number;
|
|
17
|
+
minTimeout?: number;
|
|
18
|
+
}
|
|
19
|
+
export interface GetTimeoutSignalOptions {
|
|
20
|
+
timeoutFactor?: number;
|
|
21
|
+
signal?: AbortSignal;
|
|
22
|
+
}
|
|
23
|
+
export declare class AdaptiveTimeout {
|
|
24
|
+
private readonly success;
|
|
25
|
+
private readonly failure;
|
|
26
|
+
private readonly next;
|
|
27
|
+
private readonly metric?;
|
|
28
|
+
private readonly timeoutMultiplier;
|
|
29
|
+
private readonly failureMultiplier;
|
|
30
|
+
private readonly minTimeout;
|
|
31
|
+
constructor(init?: AdaptiveTimeoutInit);
|
|
32
|
+
getTimeoutSignal(options?: GetTimeoutSignalOptions): AdaptiveTimeoutSignal;
|
|
33
|
+
cleanUp(signal: AdaptiveTimeoutSignal): void;
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=adaptive-timeout.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adaptive-timeout.d.ts","sourceRoot":"","sources":["../../src/adaptive-timeout.ts"],"names":[],"mappings":"AACA,OAAO,EAAa,KAAK,eAAe,EAAE,MAAM,YAAY,CAAA;AAE5D,OAAO,KAAK,EAAe,OAAO,EAAE,MAAM,mBAAmB,CAAA;AAE7D,eAAO,MAAM,0BAA0B,MAAM,CAAA;AAC7C,eAAO,MAAM,0BAA0B,IAAI,CAAA;AAC3C,eAAO,MAAM,mBAAmB,OAAO,CAAA;AAEvC,MAAM,WAAW,qBAAsB,SAAQ,eAAe;IAC5D,KAAK,EAAE,MAAM,CAAA;IACb,OAAO,EAAE,MAAM,CAAA;CAChB;AAED,MAAM,WAAW,mBAAmB;IAClC,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,iBAAiB,CAAC,EAAE,MAAM,CAAA;IAC1B,iBAAiB,CAAC,EAAE,MAAM,CAAA;IAC1B,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB;AAED,MAAM,WAAW,uBAAuB;IACtC,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,MAAM,CAAC,EAAE,WAAW,CAAA;CACrB;AAED,qBAAa,eAAe;IAC1B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAe;IACvC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAe;IACvC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAe;IACpC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAa;IACrC,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAQ;IAC1C,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAQ;IAC1C,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAQ;gBAEtB,IAAI,GAAE,mBAAwB;IAa3C,gBAAgB,CAAE,OAAO,GAAE,uBAA4B,GAAG,qBAAqB;IAiB/E,OAAO,CAAE,MAAM,EAAE,qBAAqB,GAAG,IAAI;CAyB9C"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { setMaxListeners } from '@libp2p/interface';
|
|
2
|
+
import { anySignal } from 'any-signal';
|
|
3
|
+
import { MovingAverage } from './moving-average.js';
|
|
4
|
+
export const DEFAULT_TIMEOUT_MULTIPLIER = 1.2;
|
|
5
|
+
export const DEFAULT_FAILURE_MULTIPLIER = 2;
|
|
6
|
+
export const DEFAULT_MIN_TIMEOUT = 2000;
|
|
7
|
+
export class AdaptiveTimeout {
|
|
8
|
+
success;
|
|
9
|
+
failure;
|
|
10
|
+
next;
|
|
11
|
+
metric;
|
|
12
|
+
timeoutMultiplier;
|
|
13
|
+
failureMultiplier;
|
|
14
|
+
minTimeout;
|
|
15
|
+
constructor(init = {}) {
|
|
16
|
+
this.success = new MovingAverage(init.interval ?? 5000);
|
|
17
|
+
this.failure = new MovingAverage(init.interval ?? 5000);
|
|
18
|
+
this.next = new MovingAverage(init.interval ?? 5000);
|
|
19
|
+
this.failureMultiplier = init.failureMultiplier ?? DEFAULT_FAILURE_MULTIPLIER;
|
|
20
|
+
this.timeoutMultiplier = init.timeoutMultiplier ?? DEFAULT_TIMEOUT_MULTIPLIER;
|
|
21
|
+
this.minTimeout = init.minTimeout ?? DEFAULT_MIN_TIMEOUT;
|
|
22
|
+
if (init.metricName != null) {
|
|
23
|
+
this.metric = init.metrics?.registerMetricGroup(init.metricName);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
getTimeoutSignal(options = {}) {
|
|
27
|
+
// calculate timeout for individual peers based on moving average of
|
|
28
|
+
// previous successful requests
|
|
29
|
+
const timeout = Math.max(Math.round(this.next.movingAverage * (options.timeoutFactor ?? this.timeoutMultiplier)), this.minTimeout);
|
|
30
|
+
const sendTimeout = AbortSignal.timeout(timeout);
|
|
31
|
+
const timeoutSignal = anySignal([options.signal, sendTimeout]);
|
|
32
|
+
setMaxListeners(Infinity, timeoutSignal, sendTimeout);
|
|
33
|
+
timeoutSignal.start = Date.now();
|
|
34
|
+
timeoutSignal.timeout = timeout;
|
|
35
|
+
return timeoutSignal;
|
|
36
|
+
}
|
|
37
|
+
cleanUp(signal) {
|
|
38
|
+
const time = Date.now() - signal.start;
|
|
39
|
+
if (signal.aborted) {
|
|
40
|
+
this.failure.push(time);
|
|
41
|
+
this.next.push(time * this.failureMultiplier);
|
|
42
|
+
this.metric?.update({
|
|
43
|
+
failureMovingAverage: this.failure.movingAverage,
|
|
44
|
+
failureDeviation: this.failure.deviation,
|
|
45
|
+
failureForecast: this.failure.forecast,
|
|
46
|
+
failureVariance: this.failure.variance,
|
|
47
|
+
failure: time
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
this.success.push(time);
|
|
52
|
+
this.next.push(time);
|
|
53
|
+
this.metric?.update({
|
|
54
|
+
successMovingAverage: this.success.movingAverage,
|
|
55
|
+
successDeviation: this.success.deviation,
|
|
56
|
+
successForecast: this.success.forecast,
|
|
57
|
+
successVariance: this.success.variance,
|
|
58
|
+
success: time
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=adaptive-timeout.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adaptive-timeout.js","sourceRoot":"","sources":["../../src/adaptive-timeout.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Implements exponential moving average. Ported from `moving-average`.
|
|
3
|
+
*
|
|
4
|
+
* @see https://en.wikipedia.org/wiki/Moving_average#Exponential_moving_average
|
|
5
|
+
* @see https://www.npmjs.com/package/moving-average
|
|
6
|
+
*/
|
|
7
|
+
export declare class MovingAverage {
|
|
8
|
+
movingAverage: number;
|
|
9
|
+
variance: number;
|
|
10
|
+
deviation: number;
|
|
11
|
+
forecast: number;
|
|
12
|
+
private readonly timespan;
|
|
13
|
+
private previousTime?;
|
|
14
|
+
constructor(timespan: number);
|
|
15
|
+
alpha(t: number, pt: number): number;
|
|
16
|
+
push(value: number, time?: number): void;
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=moving-average.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"moving-average.d.ts","sourceRoot":"","sources":["../../src/moving-average.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,qBAAa,aAAa;IACjB,aAAa,EAAE,MAAM,CAAA;IACrB,QAAQ,EAAE,MAAM,CAAA;IAChB,SAAS,EAAE,MAAM,CAAA;IACjB,QAAQ,EAAE,MAAM,CAAA;IACvB,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAQ;IACjC,OAAO,CAAC,YAAY,CAAC,CAAQ;gBAEhB,QAAQ,EAAE,MAAM;IAQ7B,KAAK,CAAE,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM;IAIrC,IAAI,CAAE,KAAK,EAAE,MAAM,EAAE,IAAI,GAAE,MAAmB,GAAG,IAAI;CAkBtD"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Implements exponential moving average. Ported from `moving-average`.
|
|
3
|
+
*
|
|
4
|
+
* @see https://en.wikipedia.org/wiki/Moving_average#Exponential_moving_average
|
|
5
|
+
* @see https://www.npmjs.com/package/moving-average
|
|
6
|
+
*/
|
|
7
|
+
export class MovingAverage {
|
|
8
|
+
movingAverage;
|
|
9
|
+
variance;
|
|
10
|
+
deviation;
|
|
11
|
+
forecast;
|
|
12
|
+
timespan;
|
|
13
|
+
previousTime;
|
|
14
|
+
constructor(timespan) {
|
|
15
|
+
this.timespan = timespan;
|
|
16
|
+
this.movingAverage = 0;
|
|
17
|
+
this.variance = 0;
|
|
18
|
+
this.deviation = 0;
|
|
19
|
+
this.forecast = 0;
|
|
20
|
+
}
|
|
21
|
+
alpha(t, pt) {
|
|
22
|
+
return 1 - (Math.exp(-(t - pt) / this.timespan));
|
|
23
|
+
}
|
|
24
|
+
push(value, time = Date.now()) {
|
|
25
|
+
if (this.previousTime != null) {
|
|
26
|
+
// calculate moving average
|
|
27
|
+
const a = this.alpha(time, this.previousTime);
|
|
28
|
+
const diff = value - this.movingAverage;
|
|
29
|
+
const incr = a * diff;
|
|
30
|
+
this.movingAverage = a * value + (1 - a) * this.movingAverage;
|
|
31
|
+
// calculate variance & deviation
|
|
32
|
+
this.variance = (1 - a) * (this.variance + diff * incr);
|
|
33
|
+
this.deviation = Math.sqrt(this.variance);
|
|
34
|
+
// calculate forecast
|
|
35
|
+
this.forecast = this.movingAverage + a * diff;
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
this.movingAverage = value;
|
|
39
|
+
}
|
|
40
|
+
this.previousTime = time;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=moving-average.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"moving-average.js","sourceRoot":"","sources":["../../src/moving-average.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,OAAO,aAAa;IACjB,aAAa,CAAQ;IACrB,QAAQ,CAAQ;IAChB,SAAS,CAAQ;IACjB,QAAQ,CAAQ;IACN,QAAQ,CAAQ;IACzB,YAAY,CAAS;IAE7B,YAAa,QAAgB;QAC3B,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAA;QACxB,IAAI,CAAC,aAAa,GAAG,CAAC,CAAA;QACtB,IAAI,CAAC,QAAQ,GAAG,CAAC,CAAA;QACjB,IAAI,CAAC,SAAS,GAAG,CAAC,CAAA;QAClB,IAAI,CAAC,QAAQ,GAAG,CAAC,CAAA;IACnB,CAAC;IAED,KAAK,CAAE,CAAS,EAAE,EAAU;QAC1B,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAA;IAClD,CAAC;IAED,IAAI,CAAE,KAAa,EAAE,OAAe,IAAI,CAAC,GAAG,EAAE;QAC5C,IAAI,IAAI,CAAC,YAAY,IAAI,IAAI,EAAE,CAAC;YAC9B,2BAA2B;YAC3B,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,IAAI,CAAC,YAAY,CAAC,CAAA;YAC7C,MAAM,IAAI,GAAG,KAAK,GAAG,IAAI,CAAC,aAAa,CAAA;YACvC,MAAM,IAAI,GAAG,CAAC,GAAG,IAAI,CAAA;YACrB,IAAI,CAAC,aAAa,GAAG,CAAC,GAAG,KAAK,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,aAAa,CAAA;YAC7D,iCAAiC;YACjC,IAAI,CAAC,QAAQ,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,GAAG,IAAI,GAAG,IAAI,CAAC,CAAA;YACvD,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;YACzC,qBAAqB;YACrB,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,aAAa,GAAG,CAAC,GAAG,IAAI,CAAA;QAC/C,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,aAAa,GAAG,KAAK,CAAA;QAC5B,CAAC;QAED,IAAI,CAAC,YAAY,GAAG,IAAI,CAAA;IAC1B,CAAC;CACF"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@libp2p/utils",
|
|
3
|
-
"version": "5.4.0-
|
|
3
|
+
"version": "5.4.0-4ad63bb79",
|
|
4
4
|
"description": "Package to aggregate shared logic and dependencies for the libp2p ecosystem",
|
|
5
5
|
"license": "Apache-2.0 OR MIT",
|
|
6
6
|
"homepage": "https://github.com/libp2p/js-libp2p/tree/main/packages/utils#readme",
|
|
@@ -56,6 +56,10 @@
|
|
|
56
56
|
"types": "./dist/src/address-sort.d.ts",
|
|
57
57
|
"import": "./dist/src/address-sort.js"
|
|
58
58
|
},
|
|
59
|
+
"./adaptive-timeout": {
|
|
60
|
+
"types": "./dist/src/adaptive-timeout.d.ts",
|
|
61
|
+
"import": "./dist/src/adaptive-timeout.js"
|
|
62
|
+
},
|
|
59
63
|
"./array-equals": {
|
|
60
64
|
"types": "./dist/src/array-equals.d.ts",
|
|
61
65
|
"import": "./dist/src/array-equals.js"
|
|
@@ -80,6 +84,10 @@
|
|
|
80
84
|
"types": "./dist/src/is-promise.d.ts",
|
|
81
85
|
"import": "./dist/src/is-promise.js"
|
|
82
86
|
},
|
|
87
|
+
"./moving-average": {
|
|
88
|
+
"types": "./dist/src/moving-average.d.ts",
|
|
89
|
+
"import": "./dist/src/moving-average.js"
|
|
90
|
+
},
|
|
83
91
|
"./multiaddr/is-loopback": {
|
|
84
92
|
"types": "./dist/src/multiaddr/is-loopback.d.ts",
|
|
85
93
|
"import": "./dist/src/multiaddr/is-loopback.js"
|
|
@@ -140,9 +148,9 @@
|
|
|
140
148
|
},
|
|
141
149
|
"dependencies": {
|
|
142
150
|
"@chainsafe/is-ip": "^2.0.2",
|
|
143
|
-
"@libp2p/crypto": "4.1.1-
|
|
144
|
-
"@libp2p/interface": "1.3.1-
|
|
145
|
-
"@libp2p/logger": "4.0.12-
|
|
151
|
+
"@libp2p/crypto": "4.1.1-4ad63bb79",
|
|
152
|
+
"@libp2p/interface": "1.3.1-4ad63bb79",
|
|
153
|
+
"@libp2p/logger": "4.0.12-4ad63bb79",
|
|
146
154
|
"@multiformats/multiaddr": "^12.2.1",
|
|
147
155
|
"@multiformats/multiaddr-matcher": "^1.2.0",
|
|
148
156
|
"@sindresorhus/fnv1a": "^3.1.0",
|
|
@@ -162,7 +170,7 @@
|
|
|
162
170
|
"uint8arrays": "^5.0.3"
|
|
163
171
|
},
|
|
164
172
|
"devDependencies": {
|
|
165
|
-
"@libp2p/peer-id-factory": "4.1.1-
|
|
173
|
+
"@libp2p/peer-id-factory": "4.1.1-4ad63bb79",
|
|
166
174
|
"@types/netmask": "^2.0.5",
|
|
167
175
|
"aegir": "^42.2.5",
|
|
168
176
|
"delay": "^6.0.0",
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { setMaxListeners } from '@libp2p/interface'
|
|
2
|
+
import { anySignal, type ClearableSignal } from 'any-signal'
|
|
3
|
+
import { MovingAverage } from './moving-average.js'
|
|
4
|
+
import type { MetricGroup, Metrics } from '@libp2p/interface'
|
|
5
|
+
|
|
6
|
+
export const DEFAULT_TIMEOUT_MULTIPLIER = 1.2
|
|
7
|
+
export const DEFAULT_FAILURE_MULTIPLIER = 2
|
|
8
|
+
export const DEFAULT_MIN_TIMEOUT = 2000
|
|
9
|
+
|
|
10
|
+
export interface AdaptiveTimeoutSignal extends ClearableSignal {
|
|
11
|
+
start: number
|
|
12
|
+
timeout: number
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface AdaptiveTimeoutInit {
|
|
16
|
+
metricName?: string
|
|
17
|
+
metrics?: Metrics
|
|
18
|
+
interval?: number
|
|
19
|
+
initialValue?: number
|
|
20
|
+
timeoutMultiplier?: number
|
|
21
|
+
failureMultiplier?: number
|
|
22
|
+
minTimeout?: number
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export interface GetTimeoutSignalOptions {
|
|
26
|
+
timeoutFactor?: number
|
|
27
|
+
signal?: AbortSignal
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export class AdaptiveTimeout {
|
|
31
|
+
private readonly success: MovingAverage
|
|
32
|
+
private readonly failure: MovingAverage
|
|
33
|
+
private readonly next: MovingAverage
|
|
34
|
+
private readonly metric?: MetricGroup
|
|
35
|
+
private readonly timeoutMultiplier: number
|
|
36
|
+
private readonly failureMultiplier: number
|
|
37
|
+
private readonly minTimeout: number
|
|
38
|
+
|
|
39
|
+
constructor (init: AdaptiveTimeoutInit = {}) {
|
|
40
|
+
this.success = new MovingAverage(init.interval ?? 5000)
|
|
41
|
+
this.failure = new MovingAverage(init.interval ?? 5000)
|
|
42
|
+
this.next = new MovingAverage(init.interval ?? 5000)
|
|
43
|
+
this.failureMultiplier = init.failureMultiplier ?? DEFAULT_FAILURE_MULTIPLIER
|
|
44
|
+
this.timeoutMultiplier = init.timeoutMultiplier ?? DEFAULT_TIMEOUT_MULTIPLIER
|
|
45
|
+
this.minTimeout = init.minTimeout ?? DEFAULT_MIN_TIMEOUT
|
|
46
|
+
|
|
47
|
+
if (init.metricName != null) {
|
|
48
|
+
this.metric = init.metrics?.registerMetricGroup(init.metricName)
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
getTimeoutSignal (options: GetTimeoutSignalOptions = {}): AdaptiveTimeoutSignal {
|
|
53
|
+
// calculate timeout for individual peers based on moving average of
|
|
54
|
+
// previous successful requests
|
|
55
|
+
const timeout = Math.max(
|
|
56
|
+
Math.round(this.next.movingAverage * (options.timeoutFactor ?? this.timeoutMultiplier)),
|
|
57
|
+
this.minTimeout
|
|
58
|
+
)
|
|
59
|
+
const sendTimeout = AbortSignal.timeout(timeout)
|
|
60
|
+
const timeoutSignal = anySignal([options.signal, sendTimeout]) as AdaptiveTimeoutSignal
|
|
61
|
+
setMaxListeners(Infinity, timeoutSignal, sendTimeout)
|
|
62
|
+
|
|
63
|
+
timeoutSignal.start = Date.now()
|
|
64
|
+
timeoutSignal.timeout = timeout
|
|
65
|
+
|
|
66
|
+
return timeoutSignal
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
cleanUp (signal: AdaptiveTimeoutSignal): void {
|
|
70
|
+
const time = Date.now() - signal.start
|
|
71
|
+
|
|
72
|
+
if (signal.aborted) {
|
|
73
|
+
this.failure.push(time)
|
|
74
|
+
this.next.push(time * this.failureMultiplier)
|
|
75
|
+
this.metric?.update({
|
|
76
|
+
failureMovingAverage: this.failure.movingAverage,
|
|
77
|
+
failureDeviation: this.failure.deviation,
|
|
78
|
+
failureForecast: this.failure.forecast,
|
|
79
|
+
failureVariance: this.failure.variance,
|
|
80
|
+
failure: time
|
|
81
|
+
})
|
|
82
|
+
} else {
|
|
83
|
+
this.success.push(time)
|
|
84
|
+
this.next.push(time)
|
|
85
|
+
this.metric?.update({
|
|
86
|
+
successMovingAverage: this.success.movingAverage,
|
|
87
|
+
successDeviation: this.success.deviation,
|
|
88
|
+
successForecast: this.success.forecast,
|
|
89
|
+
successVariance: this.success.variance,
|
|
90
|
+
success: time
|
|
91
|
+
})
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Implements exponential moving average. Ported from `moving-average`.
|
|
3
|
+
*
|
|
4
|
+
* @see https://en.wikipedia.org/wiki/Moving_average#Exponential_moving_average
|
|
5
|
+
* @see https://www.npmjs.com/package/moving-average
|
|
6
|
+
*/
|
|
7
|
+
export class MovingAverage {
|
|
8
|
+
public movingAverage: number
|
|
9
|
+
public variance: number
|
|
10
|
+
public deviation: number
|
|
11
|
+
public forecast: number
|
|
12
|
+
private readonly timespan: number
|
|
13
|
+
private previousTime?: number
|
|
14
|
+
|
|
15
|
+
constructor (timespan: number) {
|
|
16
|
+
this.timespan = timespan
|
|
17
|
+
this.movingAverage = 0
|
|
18
|
+
this.variance = 0
|
|
19
|
+
this.deviation = 0
|
|
20
|
+
this.forecast = 0
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
alpha (t: number, pt: number): number {
|
|
24
|
+
return 1 - (Math.exp(-(t - pt) / this.timespan))
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
push (value: number, time: number = Date.now()): void {
|
|
28
|
+
if (this.previousTime != null) {
|
|
29
|
+
// calculate moving average
|
|
30
|
+
const a = this.alpha(time, this.previousTime)
|
|
31
|
+
const diff = value - this.movingAverage
|
|
32
|
+
const incr = a * diff
|
|
33
|
+
this.movingAverage = a * value + (1 - a) * this.movingAverage
|
|
34
|
+
// calculate variance & deviation
|
|
35
|
+
this.variance = (1 - a) * (this.variance + diff * incr)
|
|
36
|
+
this.deviation = Math.sqrt(this.variance)
|
|
37
|
+
// calculate forecast
|
|
38
|
+
this.forecast = this.movingAverage + a * diff
|
|
39
|
+
} else {
|
|
40
|
+
this.movingAverage = value
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
this.previousTime = time
|
|
44
|
+
}
|
|
45
|
+
}
|