@fluidframework/driver-utils 0.50.3 → 0.51.2
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/packageVersion.d.ts +1 -1
- package/dist/packageVersion.js +1 -1
- package/dist/packageVersion.js.map +1 -1
- package/dist/runWithRetry.d.ts +27 -1
- package/dist/runWithRetry.d.ts.map +1 -1
- package/dist/runWithRetry.js +5 -14
- package/dist/runWithRetry.js.map +1 -1
- package/lib/packageVersion.d.ts +1 -1
- package/lib/packageVersion.js +1 -1
- package/lib/packageVersion.js.map +1 -1
- package/lib/runWithRetry.d.ts +27 -1
- package/lib/runWithRetry.d.ts.map +1 -1
- package/lib/runWithRetry.js +5 -14
- package/lib/runWithRetry.js.map +1 -1
- package/package.json +6 -6
- package/src/packageVersion.ts +1 -1
- package/src/runWithRetry.ts +34 -17
package/dist/packageVersion.d.ts
CHANGED
|
@@ -5,5 +5,5 @@
|
|
|
5
5
|
* THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY
|
|
6
6
|
*/
|
|
7
7
|
export declare const pkgName = "@fluidframework/driver-utils";
|
|
8
|
-
export declare const pkgVersion = "0.
|
|
8
|
+
export declare const pkgVersion = "0.51.2";
|
|
9
9
|
//# sourceMappingURL=packageVersion.d.ts.map
|
package/dist/packageVersion.js
CHANGED
|
@@ -8,5 +8,5 @@
|
|
|
8
8
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
9
|
exports.pkgVersion = exports.pkgName = void 0;
|
|
10
10
|
exports.pkgName = "@fluidframework/driver-utils";
|
|
11
|
-
exports.pkgVersion = "0.
|
|
11
|
+
exports.pkgVersion = "0.51.2";
|
|
12
12
|
//# sourceMappingURL=packageVersion.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"packageVersion.js","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;;AAEU,QAAA,OAAO,GAAG,8BAA8B,CAAC;AACzC,QAAA,UAAU,GAAG,QAAQ,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n *\n * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY\n */\n\nexport const pkgName = \"@fluidframework/driver-utils\";\nexport const pkgVersion = \"0.
|
|
1
|
+
{"version":3,"file":"packageVersion.js","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;;AAEU,QAAA,OAAO,GAAG,8BAA8B,CAAC;AACzC,QAAA,UAAU,GAAG,QAAQ,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n *\n * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY\n */\n\nexport const pkgName = \"@fluidframework/driver-utils\";\nexport const pkgVersion = \"0.51.2\";\n"]}
|
package/dist/runWithRetry.d.ts
CHANGED
|
@@ -3,5 +3,31 @@
|
|
|
3
3
|
* Licensed under the MIT License.
|
|
4
4
|
*/
|
|
5
5
|
import { ITelemetryLogger } from "@fluidframework/common-definitions";
|
|
6
|
-
|
|
6
|
+
/**
|
|
7
|
+
* Interface describing an object passed to various network APIs.
|
|
8
|
+
* It allows caller to control cancellation, as well as learn about any delays.
|
|
9
|
+
*/
|
|
10
|
+
export interface IProgress {
|
|
11
|
+
/**
|
|
12
|
+
* Abort signal used to cancel operation
|
|
13
|
+
* Note that most of the layers do not use this signal yet. We need to change that over time.
|
|
14
|
+
* Please consult with API documentation / implementation.
|
|
15
|
+
* Note that number of layers may not check this signal while holding this request in a queue,
|
|
16
|
+
* so it may take a while it takes effect. This can be improved in the future.
|
|
17
|
+
* Layers in question are:
|
|
18
|
+
* - driver (RateLimiter)
|
|
19
|
+
* - runWithRetry
|
|
20
|
+
*/
|
|
21
|
+
cancel?: AbortSignal;
|
|
22
|
+
/**
|
|
23
|
+
* Called whenever api returns cancellable error and the call is going to be retried.
|
|
24
|
+
* Any exception thrown from this call back result in cancellation of operation
|
|
25
|
+
* and propagation of thrown exception.
|
|
26
|
+
* @param delayInMs - delay before next retry. This value will depend on internal back-off logic,
|
|
27
|
+
* as well as information provided by service (like 429 error asking to wait for some time before retry)
|
|
28
|
+
* @param error - error object returned from the call.
|
|
29
|
+
*/
|
|
30
|
+
retry?(delayInMs: number, error: any): void;
|
|
31
|
+
}
|
|
32
|
+
export declare function runWithRetry<T>(api: (cancel?: AbortSignal) => Promise<T>, fetchCallName: string, logger: ITelemetryLogger, progress: IProgress): Promise<T>;
|
|
7
33
|
//# sourceMappingURL=runWithRetry.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runWithRetry.d.ts","sourceRoot":"","sources":["../src/runWithRetry.ts"],"names":[],"mappings":"AAAA;;;GAGG;
|
|
1
|
+
{"version":3,"file":"runWithRetry.d.ts","sourceRoot":"","sources":["../src/runWithRetry.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,oCAAoC,CAAC;AAItE;;;GAGG;AACH,MAAM,WAAW,SAAS;IACtB;;;;;;;;;OASG;IACH,MAAM,CAAC,EAAE,WAAW,CAAC;IAErB;;;;;;;OAOG;IACH,KAAK,CAAC,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,GAAG,IAAI,CAAC;CAC/C;AAED,wBAAsB,YAAY,CAAC,CAAC,EAChC,GAAG,EAAE,CAAC,MAAM,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,CAAC,CAAC,EACzC,aAAa,EAAE,MAAM,EACrB,MAAM,EAAE,gBAAgB,EACxB,QAAQ,EAAE,SAAS,GACpB,OAAO,CAAC,CAAC,CAAC,CA0CZ"}
|
package/dist/runWithRetry.js
CHANGED
|
@@ -5,10 +5,9 @@
|
|
|
5
5
|
*/
|
|
6
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
7
|
exports.runWithRetry = void 0;
|
|
8
|
-
const uuid_1 = require("uuid");
|
|
9
8
|
const common_utils_1 = require("@fluidframework/common-utils");
|
|
10
9
|
const network_1 = require("./network");
|
|
11
|
-
async function runWithRetry(api, fetchCallName,
|
|
10
|
+
async function runWithRetry(api, fetchCallName, logger, progress) {
|
|
12
11
|
var _a;
|
|
13
12
|
let result;
|
|
14
13
|
let success = false;
|
|
@@ -16,22 +15,15 @@ async function runWithRetry(api, fetchCallName, refreshDelayInfo, emitDelayInfo,
|
|
|
16
15
|
let numRetries = 0;
|
|
17
16
|
const startTime = common_utils_1.performance.now();
|
|
18
17
|
let lastError;
|
|
19
|
-
let id;
|
|
20
18
|
do {
|
|
21
19
|
try {
|
|
22
|
-
result = await api();
|
|
23
|
-
if (id !== undefined) {
|
|
24
|
-
refreshDelayInfo(id);
|
|
25
|
-
}
|
|
20
|
+
result = await api(progress.cancel);
|
|
26
21
|
success = true;
|
|
27
22
|
}
|
|
28
23
|
catch (err) {
|
|
29
|
-
if (checkRetry !== undefined) {
|
|
30
|
-
checkRetry();
|
|
31
|
-
}
|
|
32
24
|
// If it is not retriable, then just throw the error.
|
|
33
25
|
if (!network_1.canRetryOnError(err)) {
|
|
34
|
-
logger.
|
|
26
|
+
logger.sendTelemetryEvent({
|
|
35
27
|
eventName: `${fetchCallName}_cancel`,
|
|
36
28
|
retry: numRetries,
|
|
37
29
|
duration: common_utils_1.performance.now() - startTime,
|
|
@@ -43,10 +35,9 @@ async function runWithRetry(api, fetchCallName, refreshDelayInfo, emitDelayInfo,
|
|
|
43
35
|
// If the error is throttling error, then wait for the specified time before retrying.
|
|
44
36
|
// If the waitTime is not specified, then we start with retrying immediately to max of 8s.
|
|
45
37
|
retryAfterMs = (_a = network_1.getRetryDelayFromError(err)) !== null && _a !== void 0 ? _a : Math.min(retryAfterMs * 2, 8000);
|
|
46
|
-
if (
|
|
47
|
-
|
|
38
|
+
if (progress.retry) {
|
|
39
|
+
progress.retry(retryAfterMs, err);
|
|
48
40
|
}
|
|
49
|
-
emitDelayInfo(id, retryAfterMs, err);
|
|
50
41
|
await common_utils_1.delay(retryAfterMs);
|
|
51
42
|
}
|
|
52
43
|
} while (!success);
|
package/dist/runWithRetry.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runWithRetry.js","sourceRoot":"","sources":["../src/runWithRetry.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;
|
|
1
|
+
{"version":3,"file":"runWithRetry.js","sourceRoot":"","sources":["../src/runWithRetry.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAGH,+DAAkE;AAClE,uCAAoE;AA8B7D,KAAK,UAAU,YAAY,CAC9B,GAAyC,EACzC,aAAqB,EACrB,MAAwB,EACxB,QAAmB;;IAEnB,IAAI,MAAqB,CAAC;IAC1B,IAAI,OAAO,GAAG,KAAK,CAAC;IACpB,IAAI,YAAY,GAAG,IAAI,CAAC,CAAC,sBAAsB;IAC/C,IAAI,UAAU,GAAG,CAAC,CAAC;IACnB,MAAM,SAAS,GAAG,0BAAW,CAAC,GAAG,EAAE,CAAC;IACpC,IAAI,SAAc,CAAC;IACnB,GAAG;QACC,IAAI;YACA,MAAM,GAAG,MAAM,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;YACpC,OAAO,GAAG,IAAI,CAAC;SAClB;QAAC,OAAO,GAAG,EAAE;YACV,qDAAqD;YACrD,IAAI,CAAC,yBAAe,CAAC,GAAG,CAAC,EAAE;gBACvB,MAAM,CAAC,kBAAkB,CAAC;oBACtB,SAAS,EAAE,GAAG,aAAa,SAAS;oBACpC,KAAK,EAAE,UAAU;oBACjB,QAAQ,EAAE,0BAAW,CAAC,GAAG,EAAE,GAAG,SAAS;iBAC1C,EAAE,GAAG,CAAC,CAAC;gBACR,MAAM,GAAG,CAAC;aACb;YACD,UAAU,EAAE,CAAC;YACb,SAAS,GAAG,GAAG,CAAC;YAChB,sFAAsF;YACtF,0FAA0F;YAC1F,YAAY,SAAG,gCAAsB,CAAC,GAAG,CAAC,mCAAI,IAAI,CAAC,GAAG,CAAC,YAAY,GAAG,CAAC,EAAE,IAAI,CAAC,CAAC;YAC/E,IAAI,QAAQ,CAAC,KAAK,EAAE;gBAChB,QAAQ,CAAC,KAAK,CAAC,YAAY,EAAE,GAAG,CAAC,CAAC;aACrC;YACD,MAAM,oBAAK,CAAC,YAAY,CAAC,CAAC;SAC7B;KACJ,QAAQ,CAAC,OAAO,EAAE;IACnB,IAAI,UAAU,GAAG,CAAC,EAAE;QAChB,MAAM,CAAC,kBAAkB,CAAC;YACtB,SAAS,EAAE,GAAG,aAAa,YAAY;YACvC,KAAK,EAAE,UAAU;YACjB,QAAQ,EAAE,0BAAW,CAAC,GAAG,EAAE,GAAG,SAAS;SAC1C,EACD,SAAS,CAAC,CAAC;KACd;IACD,oEAAoE;IACpE,OAAO,MAAO,CAAC;AACnB,CAAC;AA/CD,oCA+CC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { ITelemetryLogger } from \"@fluidframework/common-definitions\";\nimport { delay, performance } from \"@fluidframework/common-utils\";\nimport { canRetryOnError, getRetryDelayFromError } from \"./network\";\n\n/**\n * Interface describing an object passed to various network APIs.\n * It allows caller to control cancellation, as well as learn about any delays.\n */\nexport interface IProgress {\n /**\n * Abort signal used to cancel operation\n * Note that most of the layers do not use this signal yet. We need to change that over time.\n * Please consult with API documentation / implementation.\n * Note that number of layers may not check this signal while holding this request in a queue,\n * so it may take a while it takes effect. This can be improved in the future.\n * Layers in question are:\n * - driver (RateLimiter)\n * - runWithRetry\n */\n cancel?: AbortSignal;\n\n /**\n * Called whenever api returns cancellable error and the call is going to be retried.\n * Any exception thrown from this call back result in cancellation of operation\n * and propagation of thrown exception.\n * @param delayInMs - delay before next retry. This value will depend on internal back-off logic,\n * as well as information provided by service (like 429 error asking to wait for some time before retry)\n * @param error - error object returned from the call.\n */\n retry?(delayInMs: number, error: any): void;\n}\n\nexport async function runWithRetry<T>(\n api: (cancel?: AbortSignal) => Promise<T>,\n fetchCallName: string,\n logger: ITelemetryLogger,\n progress: IProgress,\n): Promise<T> {\n let result: T | undefined;\n let success = false;\n let retryAfterMs = 1000; // has to be positive!\n let numRetries = 0;\n const startTime = performance.now();\n let lastError: any;\n do {\n try {\n result = await api(progress.cancel);\n success = true;\n } catch (err) {\n // If it is not retriable, then just throw the error.\n if (!canRetryOnError(err)) {\n logger.sendTelemetryEvent({\n eventName: `${fetchCallName}_cancel`,\n retry: numRetries,\n duration: performance.now() - startTime,\n }, err);\n throw err;\n }\n numRetries++;\n lastError = err;\n // If the error is throttling error, then wait for the specified time before retrying.\n // If the waitTime is not specified, then we start with retrying immediately to max of 8s.\n retryAfterMs = getRetryDelayFromError(err) ?? Math.min(retryAfterMs * 2, 8000);\n if (progress.retry) {\n progress.retry(retryAfterMs, err);\n }\n await delay(retryAfterMs);\n }\n } while (!success);\n if (numRetries > 0) {\n logger.sendTelemetryEvent({\n eventName: `${fetchCallName}_lastError`,\n retry: numRetries,\n duration: performance.now() - startTime,\n },\n lastError);\n }\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n return result!;\n}\n"]}
|
package/lib/packageVersion.d.ts
CHANGED
|
@@ -5,5 +5,5 @@
|
|
|
5
5
|
* THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY
|
|
6
6
|
*/
|
|
7
7
|
export declare const pkgName = "@fluidframework/driver-utils";
|
|
8
|
-
export declare const pkgVersion = "0.
|
|
8
|
+
export declare const pkgVersion = "0.51.2";
|
|
9
9
|
//# sourceMappingURL=packageVersion.d.ts.map
|
package/lib/packageVersion.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"packageVersion.js","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,CAAC,MAAM,OAAO,GAAG,8BAA8B,CAAC;AACtD,MAAM,CAAC,MAAM,UAAU,GAAG,QAAQ,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n *\n * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY\n */\n\nexport const pkgName = \"@fluidframework/driver-utils\";\nexport const pkgVersion = \"0.
|
|
1
|
+
{"version":3,"file":"packageVersion.js","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,CAAC,MAAM,OAAO,GAAG,8BAA8B,CAAC;AACtD,MAAM,CAAC,MAAM,UAAU,GAAG,QAAQ,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n *\n * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY\n */\n\nexport const pkgName = \"@fluidframework/driver-utils\";\nexport const pkgVersion = \"0.51.2\";\n"]}
|
package/lib/runWithRetry.d.ts
CHANGED
|
@@ -3,5 +3,31 @@
|
|
|
3
3
|
* Licensed under the MIT License.
|
|
4
4
|
*/
|
|
5
5
|
import { ITelemetryLogger } from "@fluidframework/common-definitions";
|
|
6
|
-
|
|
6
|
+
/**
|
|
7
|
+
* Interface describing an object passed to various network APIs.
|
|
8
|
+
* It allows caller to control cancellation, as well as learn about any delays.
|
|
9
|
+
*/
|
|
10
|
+
export interface IProgress {
|
|
11
|
+
/**
|
|
12
|
+
* Abort signal used to cancel operation
|
|
13
|
+
* Note that most of the layers do not use this signal yet. We need to change that over time.
|
|
14
|
+
* Please consult with API documentation / implementation.
|
|
15
|
+
* Note that number of layers may not check this signal while holding this request in a queue,
|
|
16
|
+
* so it may take a while it takes effect. This can be improved in the future.
|
|
17
|
+
* Layers in question are:
|
|
18
|
+
* - driver (RateLimiter)
|
|
19
|
+
* - runWithRetry
|
|
20
|
+
*/
|
|
21
|
+
cancel?: AbortSignal;
|
|
22
|
+
/**
|
|
23
|
+
* Called whenever api returns cancellable error and the call is going to be retried.
|
|
24
|
+
* Any exception thrown from this call back result in cancellation of operation
|
|
25
|
+
* and propagation of thrown exception.
|
|
26
|
+
* @param delayInMs - delay before next retry. This value will depend on internal back-off logic,
|
|
27
|
+
* as well as information provided by service (like 429 error asking to wait for some time before retry)
|
|
28
|
+
* @param error - error object returned from the call.
|
|
29
|
+
*/
|
|
30
|
+
retry?(delayInMs: number, error: any): void;
|
|
31
|
+
}
|
|
32
|
+
export declare function runWithRetry<T>(api: (cancel?: AbortSignal) => Promise<T>, fetchCallName: string, logger: ITelemetryLogger, progress: IProgress): Promise<T>;
|
|
7
33
|
//# sourceMappingURL=runWithRetry.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runWithRetry.d.ts","sourceRoot":"","sources":["../src/runWithRetry.ts"],"names":[],"mappings":"AAAA;;;GAGG;
|
|
1
|
+
{"version":3,"file":"runWithRetry.d.ts","sourceRoot":"","sources":["../src/runWithRetry.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,oCAAoC,CAAC;AAItE;;;GAGG;AACH,MAAM,WAAW,SAAS;IACtB;;;;;;;;;OASG;IACH,MAAM,CAAC,EAAE,WAAW,CAAC;IAErB;;;;;;;OAOG;IACH,KAAK,CAAC,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,GAAG,IAAI,CAAC;CAC/C;AAED,wBAAsB,YAAY,CAAC,CAAC,EAChC,GAAG,EAAE,CAAC,MAAM,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,CAAC,CAAC,EACzC,aAAa,EAAE,MAAM,EACrB,MAAM,EAAE,gBAAgB,EACxB,QAAQ,EAAE,SAAS,GACpB,OAAO,CAAC,CAAC,CAAC,CA0CZ"}
|
package/lib/runWithRetry.js
CHANGED
|
@@ -2,10 +2,9 @@
|
|
|
2
2
|
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
3
3
|
* Licensed under the MIT License.
|
|
4
4
|
*/
|
|
5
|
-
import { v4 as uuid } from "uuid";
|
|
6
5
|
import { delay, performance } from "@fluidframework/common-utils";
|
|
7
6
|
import { canRetryOnError, getRetryDelayFromError } from "./network";
|
|
8
|
-
export async function runWithRetry(api, fetchCallName,
|
|
7
|
+
export async function runWithRetry(api, fetchCallName, logger, progress) {
|
|
9
8
|
var _a;
|
|
10
9
|
let result;
|
|
11
10
|
let success = false;
|
|
@@ -13,22 +12,15 @@ export async function runWithRetry(api, fetchCallName, refreshDelayInfo, emitDel
|
|
|
13
12
|
let numRetries = 0;
|
|
14
13
|
const startTime = performance.now();
|
|
15
14
|
let lastError;
|
|
16
|
-
let id;
|
|
17
15
|
do {
|
|
18
16
|
try {
|
|
19
|
-
result = await api();
|
|
20
|
-
if (id !== undefined) {
|
|
21
|
-
refreshDelayInfo(id);
|
|
22
|
-
}
|
|
17
|
+
result = await api(progress.cancel);
|
|
23
18
|
success = true;
|
|
24
19
|
}
|
|
25
20
|
catch (err) {
|
|
26
|
-
if (checkRetry !== undefined) {
|
|
27
|
-
checkRetry();
|
|
28
|
-
}
|
|
29
21
|
// If it is not retriable, then just throw the error.
|
|
30
22
|
if (!canRetryOnError(err)) {
|
|
31
|
-
logger.
|
|
23
|
+
logger.sendTelemetryEvent({
|
|
32
24
|
eventName: `${fetchCallName}_cancel`,
|
|
33
25
|
retry: numRetries,
|
|
34
26
|
duration: performance.now() - startTime,
|
|
@@ -40,10 +32,9 @@ export async function runWithRetry(api, fetchCallName, refreshDelayInfo, emitDel
|
|
|
40
32
|
// If the error is throttling error, then wait for the specified time before retrying.
|
|
41
33
|
// If the waitTime is not specified, then we start with retrying immediately to max of 8s.
|
|
42
34
|
retryAfterMs = (_a = getRetryDelayFromError(err)) !== null && _a !== void 0 ? _a : Math.min(retryAfterMs * 2, 8000);
|
|
43
|
-
if (
|
|
44
|
-
|
|
35
|
+
if (progress.retry) {
|
|
36
|
+
progress.retry(retryAfterMs, err);
|
|
45
37
|
}
|
|
46
|
-
emitDelayInfo(id, retryAfterMs, err);
|
|
47
38
|
await delay(retryAfterMs);
|
|
48
39
|
}
|
|
49
40
|
} while (!success);
|
package/lib/runWithRetry.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runWithRetry.js","sourceRoot":"","sources":["../src/runWithRetry.ts"],"names":[],"mappings":"AAAA;;;GAGG;
|
|
1
|
+
{"version":3,"file":"runWithRetry.js","sourceRoot":"","sources":["../src/runWithRetry.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAClE,OAAO,EAAE,eAAe,EAAE,sBAAsB,EAAE,MAAM,WAAW,CAAC;AA8BpE,MAAM,CAAC,KAAK,UAAU,YAAY,CAC9B,GAAyC,EACzC,aAAqB,EACrB,MAAwB,EACxB,QAAmB;;IAEnB,IAAI,MAAqB,CAAC;IAC1B,IAAI,OAAO,GAAG,KAAK,CAAC;IACpB,IAAI,YAAY,GAAG,IAAI,CAAC,CAAC,sBAAsB;IAC/C,IAAI,UAAU,GAAG,CAAC,CAAC;IACnB,MAAM,SAAS,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC;IACpC,IAAI,SAAc,CAAC;IACnB,GAAG;QACC,IAAI;YACA,MAAM,GAAG,MAAM,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;YACpC,OAAO,GAAG,IAAI,CAAC;SAClB;QAAC,OAAO,GAAG,EAAE;YACV,qDAAqD;YACrD,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,EAAE;gBACvB,MAAM,CAAC,kBAAkB,CAAC;oBACtB,SAAS,EAAE,GAAG,aAAa,SAAS;oBACpC,KAAK,EAAE,UAAU;oBACjB,QAAQ,EAAE,WAAW,CAAC,GAAG,EAAE,GAAG,SAAS;iBAC1C,EAAE,GAAG,CAAC,CAAC;gBACR,MAAM,GAAG,CAAC;aACb;YACD,UAAU,EAAE,CAAC;YACb,SAAS,GAAG,GAAG,CAAC;YAChB,sFAAsF;YACtF,0FAA0F;YAC1F,YAAY,SAAG,sBAAsB,CAAC,GAAG,CAAC,mCAAI,IAAI,CAAC,GAAG,CAAC,YAAY,GAAG,CAAC,EAAE,IAAI,CAAC,CAAC;YAC/E,IAAI,QAAQ,CAAC,KAAK,EAAE;gBAChB,QAAQ,CAAC,KAAK,CAAC,YAAY,EAAE,GAAG,CAAC,CAAC;aACrC;YACD,MAAM,KAAK,CAAC,YAAY,CAAC,CAAC;SAC7B;KACJ,QAAQ,CAAC,OAAO,EAAE;IACnB,IAAI,UAAU,GAAG,CAAC,EAAE;QAChB,MAAM,CAAC,kBAAkB,CAAC;YACtB,SAAS,EAAE,GAAG,aAAa,YAAY;YACvC,KAAK,EAAE,UAAU;YACjB,QAAQ,EAAE,WAAW,CAAC,GAAG,EAAE,GAAG,SAAS;SAC1C,EACD,SAAS,CAAC,CAAC;KACd;IACD,oEAAoE;IACpE,OAAO,MAAO,CAAC;AACnB,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { ITelemetryLogger } from \"@fluidframework/common-definitions\";\nimport { delay, performance } from \"@fluidframework/common-utils\";\nimport { canRetryOnError, getRetryDelayFromError } from \"./network\";\n\n/**\n * Interface describing an object passed to various network APIs.\n * It allows caller to control cancellation, as well as learn about any delays.\n */\nexport interface IProgress {\n /**\n * Abort signal used to cancel operation\n * Note that most of the layers do not use this signal yet. We need to change that over time.\n * Please consult with API documentation / implementation.\n * Note that number of layers may not check this signal while holding this request in a queue,\n * so it may take a while it takes effect. This can be improved in the future.\n * Layers in question are:\n * - driver (RateLimiter)\n * - runWithRetry\n */\n cancel?: AbortSignal;\n\n /**\n * Called whenever api returns cancellable error and the call is going to be retried.\n * Any exception thrown from this call back result in cancellation of operation\n * and propagation of thrown exception.\n * @param delayInMs - delay before next retry. This value will depend on internal back-off logic,\n * as well as information provided by service (like 429 error asking to wait for some time before retry)\n * @param error - error object returned from the call.\n */\n retry?(delayInMs: number, error: any): void;\n}\n\nexport async function runWithRetry<T>(\n api: (cancel?: AbortSignal) => Promise<T>,\n fetchCallName: string,\n logger: ITelemetryLogger,\n progress: IProgress,\n): Promise<T> {\n let result: T | undefined;\n let success = false;\n let retryAfterMs = 1000; // has to be positive!\n let numRetries = 0;\n const startTime = performance.now();\n let lastError: any;\n do {\n try {\n result = await api(progress.cancel);\n success = true;\n } catch (err) {\n // If it is not retriable, then just throw the error.\n if (!canRetryOnError(err)) {\n logger.sendTelemetryEvent({\n eventName: `${fetchCallName}_cancel`,\n retry: numRetries,\n duration: performance.now() - startTime,\n }, err);\n throw err;\n }\n numRetries++;\n lastError = err;\n // If the error is throttling error, then wait for the specified time before retrying.\n // If the waitTime is not specified, then we start with retrying immediately to max of 8s.\n retryAfterMs = getRetryDelayFromError(err) ?? Math.min(retryAfterMs * 2, 8000);\n if (progress.retry) {\n progress.retry(retryAfterMs, err);\n }\n await delay(retryAfterMs);\n }\n } while (!success);\n if (numRetries > 0) {\n logger.sendTelemetryEvent({\n eventName: `${fetchCallName}_lastError`,\n retry: numRetries,\n duration: performance.now() - startTime,\n },\n lastError);\n }\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n return result!;\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fluidframework/driver-utils",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.51.2",
|
|
4
4
|
"description": "Collection of utility functions for Fluid drivers",
|
|
5
5
|
"homepage": "https://fluidframework.com",
|
|
6
6
|
"repository": "https://github.com/microsoft/FluidFramework",
|
|
@@ -62,21 +62,21 @@
|
|
|
62
62
|
"@fluidframework/gitresources": "^0.1033.0",
|
|
63
63
|
"@fluidframework/protocol-base": "^0.1033.0",
|
|
64
64
|
"@fluidframework/protocol-definitions": "^0.1025.0",
|
|
65
|
-
"@fluidframework/telemetry-utils": "^0.
|
|
65
|
+
"@fluidframework/telemetry-utils": "^0.51.2",
|
|
66
66
|
"axios": "^0.21.1",
|
|
67
67
|
"uuid": "^8.3.1"
|
|
68
68
|
},
|
|
69
69
|
"devDependencies": {
|
|
70
70
|
"@fluidframework/build-common": "^0.23.0",
|
|
71
|
-
"@fluidframework/eslint-config-fluid": "^0.
|
|
72
|
-
"@fluidframework/mocha-test-setup": "^0.
|
|
73
|
-
"@fluidframework/runtime-utils": "^0.
|
|
71
|
+
"@fluidframework/eslint-config-fluid": "^0.24.0",
|
|
72
|
+
"@fluidframework/mocha-test-setup": "^0.51.2",
|
|
73
|
+
"@fluidframework/runtime-utils": "^0.51.2",
|
|
74
74
|
"@microsoft/api-extractor": "^7.16.1",
|
|
75
75
|
"@types/mocha": "^8.2.2",
|
|
76
76
|
"@types/node": "^12.19.0",
|
|
77
77
|
"@typescript-eslint/eslint-plugin": "~4.14.0",
|
|
78
78
|
"@typescript-eslint/parser": "~4.14.0",
|
|
79
|
-
"concurrently": "^
|
|
79
|
+
"concurrently": "^6.2.0",
|
|
80
80
|
"copyfiles": "^2.1.0",
|
|
81
81
|
"cross-env": "^7.0.2",
|
|
82
82
|
"eslint": "~7.18.0",
|
package/src/packageVersion.ts
CHANGED
package/src/runWithRetry.ts
CHANGED
|
@@ -3,18 +3,43 @@
|
|
|
3
3
|
* Licensed under the MIT License.
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import { v4 as uuid } from "uuid";
|
|
7
6
|
import { ITelemetryLogger } from "@fluidframework/common-definitions";
|
|
8
7
|
import { delay, performance } from "@fluidframework/common-utils";
|
|
9
8
|
import { canRetryOnError, getRetryDelayFromError } from "./network";
|
|
10
9
|
|
|
10
|
+
/**
|
|
11
|
+
* Interface describing an object passed to various network APIs.
|
|
12
|
+
* It allows caller to control cancellation, as well as learn about any delays.
|
|
13
|
+
*/
|
|
14
|
+
export interface IProgress {
|
|
15
|
+
/**
|
|
16
|
+
* Abort signal used to cancel operation
|
|
17
|
+
* Note that most of the layers do not use this signal yet. We need to change that over time.
|
|
18
|
+
* Please consult with API documentation / implementation.
|
|
19
|
+
* Note that number of layers may not check this signal while holding this request in a queue,
|
|
20
|
+
* so it may take a while it takes effect. This can be improved in the future.
|
|
21
|
+
* Layers in question are:
|
|
22
|
+
* - driver (RateLimiter)
|
|
23
|
+
* - runWithRetry
|
|
24
|
+
*/
|
|
25
|
+
cancel?: AbortSignal;
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Called whenever api returns cancellable error and the call is going to be retried.
|
|
29
|
+
* Any exception thrown from this call back result in cancellation of operation
|
|
30
|
+
* and propagation of thrown exception.
|
|
31
|
+
* @param delayInMs - delay before next retry. This value will depend on internal back-off logic,
|
|
32
|
+
* as well as information provided by service (like 429 error asking to wait for some time before retry)
|
|
33
|
+
* @param error - error object returned from the call.
|
|
34
|
+
*/
|
|
35
|
+
retry?(delayInMs: number, error: any): void;
|
|
36
|
+
}
|
|
37
|
+
|
|
11
38
|
export async function runWithRetry<T>(
|
|
12
|
-
api: () => Promise<T>,
|
|
39
|
+
api: (cancel?: AbortSignal) => Promise<T>,
|
|
13
40
|
fetchCallName: string,
|
|
14
|
-
refreshDelayInfo: (id: string) => void,
|
|
15
|
-
emitDelayInfo: (id: string, retryInMs: number, err: any) => void,
|
|
16
41
|
logger: ITelemetryLogger,
|
|
17
|
-
|
|
42
|
+
progress: IProgress,
|
|
18
43
|
): Promise<T> {
|
|
19
44
|
let result: T | undefined;
|
|
20
45
|
let success = false;
|
|
@@ -22,21 +47,14 @@ export async function runWithRetry<T>(
|
|
|
22
47
|
let numRetries = 0;
|
|
23
48
|
const startTime = performance.now();
|
|
24
49
|
let lastError: any;
|
|
25
|
-
let id: string | undefined;
|
|
26
50
|
do {
|
|
27
51
|
try {
|
|
28
|
-
result = await api();
|
|
29
|
-
if (id !== undefined) {
|
|
30
|
-
refreshDelayInfo(id);
|
|
31
|
-
}
|
|
52
|
+
result = await api(progress.cancel);
|
|
32
53
|
success = true;
|
|
33
54
|
} catch (err) {
|
|
34
|
-
if (checkRetry !== undefined) {
|
|
35
|
-
checkRetry();
|
|
36
|
-
}
|
|
37
55
|
// If it is not retriable, then just throw the error.
|
|
38
56
|
if (!canRetryOnError(err)) {
|
|
39
|
-
logger.
|
|
57
|
+
logger.sendTelemetryEvent({
|
|
40
58
|
eventName: `${fetchCallName}_cancel`,
|
|
41
59
|
retry: numRetries,
|
|
42
60
|
duration: performance.now() - startTime,
|
|
@@ -48,10 +66,9 @@ export async function runWithRetry<T>(
|
|
|
48
66
|
// If the error is throttling error, then wait for the specified time before retrying.
|
|
49
67
|
// If the waitTime is not specified, then we start with retrying immediately to max of 8s.
|
|
50
68
|
retryAfterMs = getRetryDelayFromError(err) ?? Math.min(retryAfterMs * 2, 8000);
|
|
51
|
-
if (
|
|
52
|
-
|
|
69
|
+
if (progress.retry) {
|
|
70
|
+
progress.retry(retryAfterMs, err);
|
|
53
71
|
}
|
|
54
|
-
emitDelayInfo(id, retryAfterMs, err);
|
|
55
72
|
await delay(retryAfterMs);
|
|
56
73
|
}
|
|
57
74
|
} while (!success);
|