@splitsoftware/splitio-commons 3.1.1-rc.7 → 3.1.1-rc.9
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/cjs/sdkClient/sdkLifecycle.js +3 -2
- package/cjs/services/authProvider.js +4 -3
- package/cjs/utils/Backoff.js +12 -4
- package/esm/sdkClient/sdkLifecycle.js +3 -2
- package/esm/services/authProvider.js +4 -3
- package/esm/utils/Backoff.js +12 -4
- package/package.json +3 -3
- package/src/sdkClient/sdkLifecycle.ts +4 -2
- package/src/services/authProvider.ts +5 -4
- package/src/utils/Backoff.ts +14 -4
|
@@ -61,9 +61,10 @@ function sdkLifecycleFactory(params, isSharedClient) {
|
|
|
61
61
|
}
|
|
62
62
|
// Stop background jobs
|
|
63
63
|
syncManager && syncManager.stop();
|
|
64
|
+
// Stop the service API (the auth provider backoff retries specifically) before flushing,
|
|
65
|
+
// so that a pending/never-resolved auth retry doesn't block the flush forever
|
|
66
|
+
serviceApi && serviceApi.stop();
|
|
64
67
|
return __flush().then(function () {
|
|
65
|
-
// Stop the service API (the auth provider backoff retries specifically) after the final flush, so it can still authenticate using the still-valid cached credential
|
|
66
|
-
serviceApi && serviceApi.stop();
|
|
67
68
|
// Cleanup storage
|
|
68
69
|
return storage.destroy();
|
|
69
70
|
});
|
|
@@ -45,7 +45,7 @@ function authProviderFactory(settings, splitHttpClient, telemetryTracker) {
|
|
|
45
45
|
}
|
|
46
46
|
return {
|
|
47
47
|
credential: function () {
|
|
48
|
-
if (cachedCredential && !isExpired(cachedCredential)) {
|
|
48
|
+
if (stopped || (cachedCredential && !isExpired(cachedCredential))) {
|
|
49
49
|
return Promise.resolve(cachedCredential);
|
|
50
50
|
}
|
|
51
51
|
if (cachedCredential)
|
|
@@ -57,9 +57,10 @@ function authProviderFactory(settings, splitHttpClient, telemetryTracker) {
|
|
|
57
57
|
},
|
|
58
58
|
stop: function () {
|
|
59
59
|
stopped = true;
|
|
60
|
-
cachedCredential = undefined;
|
|
61
60
|
inFlightPromise = undefined;
|
|
62
|
-
|
|
61
|
+
// Keep any already-cached credential usable (e.g. by a final flush on destroy).
|
|
62
|
+
// Pass it to reset() so a pending retry's promise settles with it immediately.
|
|
63
|
+
backoff.reset(cachedCredential);
|
|
63
64
|
}
|
|
64
65
|
};
|
|
65
66
|
}
|
package/cjs/utils/Backoff.js
CHANGED
|
@@ -3,7 +3,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.Backoff = void 0;
|
|
4
4
|
var Backoff = /** @class */ (function () {
|
|
5
5
|
/**
|
|
6
|
-
* Schedule function calls with exponential backoff
|
|
6
|
+
* Schedule function calls with exponential backoff.
|
|
7
|
+
* @param cb - The function to call. Must return a promise if used with `scheduleCallAsync`.
|
|
7
8
|
*/
|
|
8
9
|
function Backoff(cb, baseMillis, maxMillis) {
|
|
9
10
|
this.baseMillis = Backoff.__TEST__BASE_MILLIS || baseMillis || Backoff.DEFAULT_BASE_MILLIS;
|
|
@@ -20,11 +21,11 @@ var Backoff = /** @class */ (function () {
|
|
|
20
21
|
var delayInMillis = Math.min(this.baseMillis * Math.pow(2, this.attempts), this.maxMillis);
|
|
21
22
|
if (this.timeoutID)
|
|
22
23
|
clearTimeout(this.timeoutID);
|
|
24
|
+
this.attempts++;
|
|
23
25
|
this.timeoutID = setTimeout(function () {
|
|
24
26
|
_this.timeoutID = undefined;
|
|
25
27
|
_this.cb();
|
|
26
28
|
}, delayInMillis);
|
|
27
|
-
this.attempts++;
|
|
28
29
|
return delayInMillis;
|
|
29
30
|
};
|
|
30
31
|
/**
|
|
@@ -38,21 +39,28 @@ var Backoff = /** @class */ (function () {
|
|
|
38
39
|
clearTimeout(this.timeoutID);
|
|
39
40
|
this.attempts++;
|
|
40
41
|
return new Promise(function (resolve, reject) {
|
|
42
|
+
_this.pendingResolve = resolve;
|
|
41
43
|
_this.timeoutID = setTimeout(function () {
|
|
42
44
|
_this.timeoutID = undefined;
|
|
45
|
+
_this.pendingResolve = undefined;
|
|
43
46
|
_this.cb().then(resolve, reject);
|
|
44
47
|
}, delayInMillis);
|
|
45
48
|
});
|
|
46
49
|
};
|
|
47
50
|
/**
|
|
48
|
-
* Reset the backoff attempts
|
|
51
|
+
* Reset the backoff attempts, canceling any scheduled `cb` call. If a `scheduleCallAsync` call is pending,
|
|
52
|
+
* its promise is resolved immediately with provided `value`, instead of invoking `cb` again.
|
|
49
53
|
*/
|
|
50
|
-
Backoff.prototype.reset = function () {
|
|
54
|
+
Backoff.prototype.reset = function (value) {
|
|
51
55
|
this.attempts = 0;
|
|
52
56
|
if (this.timeoutID) {
|
|
53
57
|
clearTimeout(this.timeoutID);
|
|
54
58
|
this.timeoutID = undefined;
|
|
55
59
|
}
|
|
60
|
+
if (this.pendingResolve) {
|
|
61
|
+
this.pendingResolve(value);
|
|
62
|
+
this.pendingResolve = undefined;
|
|
63
|
+
}
|
|
56
64
|
};
|
|
57
65
|
Backoff.DEFAULT_BASE_MILLIS = 1000; // 1 second
|
|
58
66
|
Backoff.DEFAULT_MAX_MILLIS = 1800000; // 30 minutes
|
|
@@ -58,9 +58,10 @@ export function sdkLifecycleFactory(params, isSharedClient) {
|
|
|
58
58
|
}
|
|
59
59
|
// Stop background jobs
|
|
60
60
|
syncManager && syncManager.stop();
|
|
61
|
+
// Stop the service API (the auth provider backoff retries specifically) before flushing,
|
|
62
|
+
// so that a pending/never-resolved auth retry doesn't block the flush forever
|
|
63
|
+
serviceApi && serviceApi.stop();
|
|
61
64
|
return __flush().then(function () {
|
|
62
|
-
// Stop the service API (the auth provider backoff retries specifically) after the final flush, so it can still authenticate using the still-valid cached credential
|
|
63
|
-
serviceApi && serviceApi.stop();
|
|
64
65
|
// Cleanup storage
|
|
65
66
|
return storage.destroy();
|
|
66
67
|
});
|
|
@@ -42,7 +42,7 @@ export function authProviderFactory(settings, splitHttpClient, telemetryTracker)
|
|
|
42
42
|
}
|
|
43
43
|
return {
|
|
44
44
|
credential: function () {
|
|
45
|
-
if (cachedCredential && !isExpired(cachedCredential)) {
|
|
45
|
+
if (stopped || (cachedCredential && !isExpired(cachedCredential))) {
|
|
46
46
|
return Promise.resolve(cachedCredential);
|
|
47
47
|
}
|
|
48
48
|
if (cachedCredential)
|
|
@@ -54,9 +54,10 @@ export function authProviderFactory(settings, splitHttpClient, telemetryTracker)
|
|
|
54
54
|
},
|
|
55
55
|
stop: function () {
|
|
56
56
|
stopped = true;
|
|
57
|
-
cachedCredential = undefined;
|
|
58
57
|
inFlightPromise = undefined;
|
|
59
|
-
|
|
58
|
+
// Keep any already-cached credential usable (e.g. by a final flush on destroy).
|
|
59
|
+
// Pass it to reset() so a pending retry's promise settles with it immediately.
|
|
60
|
+
backoff.reset(cachedCredential);
|
|
60
61
|
}
|
|
61
62
|
};
|
|
62
63
|
}
|
package/esm/utils/Backoff.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
var Backoff = /** @class */ (function () {
|
|
2
2
|
/**
|
|
3
|
-
* Schedule function calls with exponential backoff
|
|
3
|
+
* Schedule function calls with exponential backoff.
|
|
4
|
+
* @param cb - The function to call. Must return a promise if used with `scheduleCallAsync`.
|
|
4
5
|
*/
|
|
5
6
|
function Backoff(cb, baseMillis, maxMillis) {
|
|
6
7
|
this.baseMillis = Backoff.__TEST__BASE_MILLIS || baseMillis || Backoff.DEFAULT_BASE_MILLIS;
|
|
@@ -17,11 +18,11 @@ var Backoff = /** @class */ (function () {
|
|
|
17
18
|
var delayInMillis = Math.min(this.baseMillis * Math.pow(2, this.attempts), this.maxMillis);
|
|
18
19
|
if (this.timeoutID)
|
|
19
20
|
clearTimeout(this.timeoutID);
|
|
21
|
+
this.attempts++;
|
|
20
22
|
this.timeoutID = setTimeout(function () {
|
|
21
23
|
_this.timeoutID = undefined;
|
|
22
24
|
_this.cb();
|
|
23
25
|
}, delayInMillis);
|
|
24
|
-
this.attempts++;
|
|
25
26
|
return delayInMillis;
|
|
26
27
|
};
|
|
27
28
|
/**
|
|
@@ -35,21 +36,28 @@ var Backoff = /** @class */ (function () {
|
|
|
35
36
|
clearTimeout(this.timeoutID);
|
|
36
37
|
this.attempts++;
|
|
37
38
|
return new Promise(function (resolve, reject) {
|
|
39
|
+
_this.pendingResolve = resolve;
|
|
38
40
|
_this.timeoutID = setTimeout(function () {
|
|
39
41
|
_this.timeoutID = undefined;
|
|
42
|
+
_this.pendingResolve = undefined;
|
|
40
43
|
_this.cb().then(resolve, reject);
|
|
41
44
|
}, delayInMillis);
|
|
42
45
|
});
|
|
43
46
|
};
|
|
44
47
|
/**
|
|
45
|
-
* Reset the backoff attempts
|
|
48
|
+
* Reset the backoff attempts, canceling any scheduled `cb` call. If a `scheduleCallAsync` call is pending,
|
|
49
|
+
* its promise is resolved immediately with provided `value`, instead of invoking `cb` again.
|
|
46
50
|
*/
|
|
47
|
-
Backoff.prototype.reset = function () {
|
|
51
|
+
Backoff.prototype.reset = function (value) {
|
|
48
52
|
this.attempts = 0;
|
|
49
53
|
if (this.timeoutID) {
|
|
50
54
|
clearTimeout(this.timeoutID);
|
|
51
55
|
this.timeoutID = undefined;
|
|
52
56
|
}
|
|
57
|
+
if (this.pendingResolve) {
|
|
58
|
+
this.pendingResolve(value);
|
|
59
|
+
this.pendingResolve = undefined;
|
|
60
|
+
}
|
|
53
61
|
};
|
|
54
62
|
Backoff.DEFAULT_BASE_MILLIS = 1000; // 1 second
|
|
55
63
|
Backoff.DEFAULT_MAX_MILLIS = 1800000; // 30 minutes
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@splitsoftware/splitio-commons",
|
|
3
|
-
"version": "3.1.1-rc.
|
|
3
|
+
"version": "3.1.1-rc.9",
|
|
4
4
|
"description": "Split JavaScript SDK common components",
|
|
5
5
|
"main": "cjs/index.js",
|
|
6
6
|
"module": "esm/index.js",
|
|
@@ -20,8 +20,8 @@
|
|
|
20
20
|
"check:lint": "eslint src types --ext .js,.ts",
|
|
21
21
|
"check:types": "tsc --noEmit",
|
|
22
22
|
"build": "npm run build:cjs && npm run build:esm",
|
|
23
|
-
"build:esm": "rimraf esm && tsc -m es2015 --outDir esm",
|
|
24
|
-
"build:cjs": "rimraf cjs && tsc -m CommonJS --outDir cjs",
|
|
23
|
+
"build:esm": "rimraf esm && tsc -p tsconfig.build.json -m es2015 --outDir esm",
|
|
24
|
+
"build:cjs": "rimraf cjs && tsc -p tsconfig.build.json -m CommonJS --outDir cjs",
|
|
25
25
|
"test": "jest",
|
|
26
26
|
"test:coverage": "jest --coverage",
|
|
27
27
|
"all": "npm run check && npm run build && npm run test",
|
|
@@ -70,9 +70,11 @@ export function sdkLifecycleFactory(params: ISdkFactoryContext, isSharedClient?:
|
|
|
70
70
|
// Stop background jobs
|
|
71
71
|
syncManager && syncManager.stop();
|
|
72
72
|
|
|
73
|
+
// Stop the service API (the auth provider backoff retries specifically) before flushing,
|
|
74
|
+
// so that a pending/never-resolved auth retry doesn't block the flush forever
|
|
75
|
+
serviceApi && serviceApi.stop();
|
|
76
|
+
|
|
73
77
|
return __flush().then(() => {
|
|
74
|
-
// Stop the service API (the auth provider backoff retries specifically) after the final flush, so it can still authenticate using the still-valid cached credential
|
|
75
|
-
serviceApi && serviceApi.stop();
|
|
76
78
|
// Cleanup storage
|
|
77
79
|
return storage.destroy();
|
|
78
80
|
});
|
|
@@ -69,8 +69,8 @@ export function authProviderFactory(settings: ISettings, splitHttpClient: ISplit
|
|
|
69
69
|
|
|
70
70
|
return {
|
|
71
71
|
credential(): Promise<IJwtCredential> {
|
|
72
|
-
if (cachedCredential && !isExpired(cachedCredential)) {
|
|
73
|
-
return Promise.resolve(cachedCredential);
|
|
72
|
+
if (stopped || (cachedCredential && !isExpired(cachedCredential))) {
|
|
73
|
+
return Promise.resolve(cachedCredential!);
|
|
74
74
|
}
|
|
75
75
|
|
|
76
76
|
if (cachedCredential) log.debug(LOG_PREFIX_SYNC_AUTH + 'cached credential expired');
|
|
@@ -84,9 +84,10 @@ export function authProviderFactory(settings: ISettings, splitHttpClient: ISplit
|
|
|
84
84
|
|
|
85
85
|
stop() {
|
|
86
86
|
stopped = true;
|
|
87
|
-
cachedCredential = undefined;
|
|
88
87
|
inFlightPromise = undefined;
|
|
89
|
-
|
|
88
|
+
// Keep any already-cached credential usable (e.g. by a final flush on destroy).
|
|
89
|
+
// Pass it to reset() so a pending retry's promise settles with it immediately.
|
|
90
|
+
backoff.reset(cachedCredential);
|
|
90
91
|
}
|
|
91
92
|
};
|
|
92
93
|
}
|
package/src/utils/Backoff.ts
CHANGED
|
@@ -12,9 +12,11 @@ export class Backoff {
|
|
|
12
12
|
attempts: number;
|
|
13
13
|
cb: (...args: any[]) => any;
|
|
14
14
|
timeoutID: ReturnType<typeof setTimeout> | undefined;
|
|
15
|
+
pendingResolve: ((value: any) => void) | undefined;
|
|
15
16
|
|
|
16
17
|
/**
|
|
17
|
-
* Schedule function calls with exponential backoff
|
|
18
|
+
* Schedule function calls with exponential backoff.
|
|
19
|
+
* @param cb - The function to call. Must return a promise if used with `scheduleCallAsync`.
|
|
18
20
|
*/
|
|
19
21
|
constructor(cb: (...args: any[]) => any, baseMillis?: number, maxMillis?: number) {
|
|
20
22
|
this.baseMillis = Backoff.__TEST__BASE_MILLIS || baseMillis || Backoff.DEFAULT_BASE_MILLIS;
|
|
@@ -31,11 +33,12 @@ export class Backoff {
|
|
|
31
33
|
let delayInMillis = Math.min(this.baseMillis * Math.pow(2, this.attempts), this.maxMillis);
|
|
32
34
|
|
|
33
35
|
if (this.timeoutID) clearTimeout(this.timeoutID);
|
|
36
|
+
this.attempts++;
|
|
37
|
+
|
|
34
38
|
this.timeoutID = setTimeout(() => {
|
|
35
39
|
this.timeoutID = undefined;
|
|
36
40
|
this.cb();
|
|
37
41
|
}, delayInMillis);
|
|
38
|
-
this.attempts++;
|
|
39
42
|
|
|
40
43
|
return delayInMillis;
|
|
41
44
|
}
|
|
@@ -51,22 +54,29 @@ export class Backoff {
|
|
|
51
54
|
this.attempts++;
|
|
52
55
|
|
|
53
56
|
return new Promise<T>((resolve, reject) => {
|
|
57
|
+
this.pendingResolve = resolve;
|
|
54
58
|
this.timeoutID = setTimeout(() => {
|
|
55
59
|
this.timeoutID = undefined;
|
|
60
|
+
this.pendingResolve = undefined;
|
|
56
61
|
this.cb().then(resolve, reject);
|
|
57
62
|
}, delayInMillis);
|
|
58
63
|
});
|
|
59
64
|
}
|
|
60
65
|
|
|
61
66
|
/**
|
|
62
|
-
* Reset the backoff attempts
|
|
67
|
+
* Reset the backoff attempts, canceling any scheduled `cb` call. If a `scheduleCallAsync` call is pending,
|
|
68
|
+
* its promise is resolved immediately with provided `value`, instead of invoking `cb` again.
|
|
63
69
|
*/
|
|
64
|
-
reset() {
|
|
70
|
+
reset<T>(value?: T) {
|
|
65
71
|
this.attempts = 0;
|
|
66
72
|
if (this.timeoutID) {
|
|
67
73
|
clearTimeout(this.timeoutID);
|
|
68
74
|
this.timeoutID = undefined;
|
|
69
75
|
}
|
|
76
|
+
if (this.pendingResolve) {
|
|
77
|
+
this.pendingResolve(value);
|
|
78
|
+
this.pendingResolve = undefined;
|
|
79
|
+
}
|
|
70
80
|
}
|
|
71
81
|
|
|
72
82
|
}
|