@fluidframework/driver-utils 2.0.0-internal.7.2.1 → 2.0.0-internal.7.3.0

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/CHANGELOG.md CHANGED
@@ -1,5 +1,9 @@
1
1
  # @fluidframework/driver-utils
2
2
 
3
+ ## 2.0.0-internal.7.3.0
4
+
5
+ Dependency updates only.
6
+
3
7
  ## 2.0.0-internal.7.2.0
4
8
 
5
9
  Dependency updates only.
package/README.md CHANGED
@@ -63,8 +63,7 @@ Thank you!
63
63
 
64
64
  This project may contain Microsoft trademarks or logos for Microsoft projects, products, or services.
65
65
 
66
- Use of these trademarks or logos must follow Microsoft's [Trademark & Brand
67
- Guidelines](https://www.microsoft.com/en-us/legal/intellectualproperty/trademarks/usage/general).
66
+ Use of these trademarks or logos must follow Microsoft's [Trademark & Brand Guidelines](https://www.microsoft.com/en-us/legal/intellectualproperty/trademarks/usage/general).
68
67
 
69
68
  Use of Microsoft trademarks or logos in modified versions of this project must not cause confusion or imply Microsoft sponsorship.
70
69
 
@@ -90,7 +90,7 @@ export class BlobTreeEntry {
90
90
  export function buildSnapshotTree(entries: ITreeEntry[], blobMap: Map<string, ArrayBufferLike>): ISnapshotTree;
91
91
 
92
92
  // @public
93
- export function calculateMaxWaitTime(error: unknown): number;
93
+ export function calculateMaxWaitTime(delayMs: number, error: unknown): number;
94
94
 
95
95
  // @public (undocumented)
96
96
  export function canBeCoalescedByService(message: ISequencedDocumentMessage | IDocumentMessage): boolean;
@@ -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 = "2.0.0-internal.7.2.1";
8
+ export declare const pkgVersion = "2.0.0-internal.7.3.0";
9
9
  //# sourceMappingURL=packageVersion.d.ts.map
@@ -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 = "2.0.0-internal.7.2.1";
11
+ exports.pkgVersion = "2.0.0-internal.7.3.0";
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,sBAAsB,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 = \"2.0.0-internal.7.2.1\";\n"]}
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,sBAAsB,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 = \"2.0.0-internal.7.3.0\";\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"parallelRequests.d.ts","sourceRoot":"","sources":["../src/parallelRequests.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"parallelRequests.d.ts","sourceRoot":"","sources":["../src/parallelRequests.ts"],"names":[],"mappings":"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"}
@@ -12,8 +12,9 @@ const network_1 = require("./network");
12
12
  const networkUtils_1 = require("./networkUtils");
13
13
  // For now, this package is versioned and released in unison with the specific drivers
14
14
  const packageVersion_1 = require("./packageVersion");
15
- const MaxFetchDelayInMs = 10000;
16
- const MissingFetchDelayInMs = 100;
15
+ const runWithRetry_1 = require("./runWithRetry");
16
+ // We double this value in first try in when we calculate time to wait for in "calculateMaxWaitTime" function.
17
+ const MissingFetchDelayInMs = 50;
17
18
  /**
18
19
  * Helper class to organize parallel fetching of data
19
20
  * It can be used to concurrently do many requests, while consuming
@@ -339,9 +340,10 @@ async function getSingleOpBatch(get, props, strongTo, logger, signal, scenarioNa
339
340
  let retry = 0;
340
341
  const nothing = { partial: false, cancel: true, payload: [] };
341
342
  let waitStartTime = 0;
343
+ let waitTime = MissingFetchDelayInMs;
342
344
  while (signal?.aborted !== true) {
343
345
  retry++;
344
- let delay = Math.min(MaxFetchDelayInMs, MissingFetchDelayInMs * Math.pow(2, retry));
346
+ let lastError;
345
347
  const startTime = client_utils_1.performance.now();
346
348
  try {
347
349
  // Issue async request for deltas
@@ -378,6 +380,7 @@ async function getSingleOpBatch(get, props, strongTo, logger, signal, scenarioNa
378
380
  }
379
381
  }
380
382
  catch (error) {
383
+ lastError = error;
381
384
  const canRetry = (0, network_1.canRetryOnError)(error);
382
385
  const retryAfter = (0, network_1.getRetryDelayFromError)(error);
383
386
  // This will log to error table only if the error is non-retryable
@@ -393,10 +396,6 @@ async function getSingleOpBatch(get, props, strongTo, logger, signal, scenarioNa
393
396
  // It's game over scenario.
394
397
  throw error;
395
398
  }
396
- if (retryAfter !== undefined) {
397
- // If the error told us to wait, then we will wait for that specific amount rather than the default.
398
- delay = retryAfter;
399
- }
400
399
  }
401
400
  if (telemetryEvent === undefined) {
402
401
  waitStartTime = client_utils_1.performance.now();
@@ -404,10 +403,11 @@ async function getSingleOpBatch(get, props, strongTo, logger, signal, scenarioNa
404
403
  eventName: "GetDeltasWaitTime",
405
404
  });
406
405
  }
406
+ waitTime = (0, runWithRetry_1.calculateMaxWaitTime)(waitTime, lastError);
407
407
  // If we get here something has gone wrong - either got an unexpected empty set of messages back or a real error.
408
408
  // Either way we will wait a little bit before retrying.
409
409
  await new Promise((resolve) => {
410
- setTimeout(resolve, delay);
410
+ setTimeout(resolve, waitTime);
411
411
  });
412
412
  // If we believe we're offline, we assume there's no point in trying until we at least think we're online.
413
413
  // NOTE: This isn't strictly true for drivers that don't require network (e.g. local driver). Really this logic
@@ -1 +1 @@
1
- {"version":3,"file":"parallelRequests.js","sourceRoot":"","sources":["../src/parallelRequests.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\nimport { performance } from \"@fluid-internal/client-utils\";\nimport { ITelemetryProperties } from \"@fluidframework/core-interfaces\";\nimport { assert, Deferred } from \"@fluidframework/core-utils\";\nimport { ITelemetryLoggerExt, PerformanceEvent } from \"@fluidframework/telemetry-utils\";\nimport { ISequencedDocumentMessage } from \"@fluidframework/protocol-definitions\";\nimport { IDeltasFetchResult, IStream, IStreamResult } from \"@fluidframework/driver-definitions\";\nimport { getRetryDelayFromError, canRetryOnError, createGenericNetworkError } from \"./network\";\nimport { logNetworkFailure } from \"./networkUtils\";\n// For now, this package is versioned and released in unison with the specific drivers\nimport { pkgVersion as driverVersion } from \"./packageVersion\";\n\nconst MaxFetchDelayInMs = 10000;\nconst MissingFetchDelayInMs = 100;\n\ntype WorkingState = \"working\" | \"done\" | \"canceled\";\n\n/**\n * Helper class to organize parallel fetching of data\n * It can be used to concurrently do many requests, while consuming\n * data in the right order. Take a look at UT for examples.\n * @param concurrency - level of concurrency\n * @param from - starting point of fetching data (inclusive)\n * @param to - ending point of fetching data. exclusive, or undefined if unknown\n * @param payloadSize - batch size\n * @param logger - logger to use\n * @param requestCallback - callback to request batches\n * @returns Queue that can be used to retrieve data\n * @public\n */\nexport class ParallelRequests<T> {\n\tprivate latestRequested: number;\n\tprivate nextToDeliver: number;\n\tprivate readonly results = new Map<number, T[]>();\n\tprivate workingState: WorkingState = \"working\";\n\tprivate requestsInFlight = 0;\n\tprivate readonly endEvent = new Deferred<void>();\n\tprivate requests = 0;\n\tprivate readonly knewTo: boolean;\n\n\tprivate get working() {\n\t\treturn this.workingState === \"working\";\n\t}\n\tpublic get canceled() {\n\t\treturn this.workingState === \"canceled\";\n\t}\n\n\tconstructor(\n\t\tfrom: number,\n\t\tprivate to: number | undefined,\n\t\tprivate readonly payloadSize: number,\n\t\tprivate readonly logger: ITelemetryLoggerExt,\n\t\tprivate readonly requestCallback: (\n\t\t\trequest: number,\n\t\t\tfrom: number,\n\t\t\tto: number,\n\t\t\tstrongTo: boolean,\n\t\t\tprops: ITelemetryProperties,\n\t\t) => Promise<{ partial: boolean; cancel: boolean; payload: T[] }>,\n\t\tprivate readonly responseCallback: (payload: T[]) => void,\n\t) {\n\t\tthis.latestRequested = from;\n\t\tthis.nextToDeliver = from;\n\t\tthis.knewTo = to !== undefined;\n\t}\n\n\tpublic cancel() {\n\t\tif (this.working) {\n\t\t\tthis.workingState = \"canceled\";\n\t\t\tthis.endEvent.resolve();\n\t\t}\n\t}\n\n\tpublic async run(concurrency: number) {\n\t\tassert(concurrency > 0, 0x102 /* \"invalid level of concurrency\" */);\n\t\tassert(this.working, 0x103 /* \"trying to parallel run while not working\" */);\n\n\t\tlet c = concurrency;\n\t\twhile (c > 0) {\n\t\t\tc--;\n\t\t\tthis.addRequest();\n\t\t}\n\t\tthis.dispatch(); // will recalculate and trigger this.endEvent if needed\n\t\treturn this.endEvent.promise;\n\t}\n\n\tprivate done() {\n\t\t// We should satisfy request fully.\n\t\tassert(this.to !== undefined, 0x104 /* \"undefined end point for parallel fetch\" */);\n\t\tassert(\n\t\t\tthis.nextToDeliver >= this.to,\n\t\t\t0x105 /* \"unexpected end point for parallel fetch\" */,\n\t\t);\n\t\tif (this.working) {\n\t\t\tthis.workingState = \"done\";\n\t\t\tthis.endEvent.resolve();\n\t\t}\n\t}\n\n\tprivate fail(error) {\n\t\tif (this.working) {\n\t\t\tthis.workingState = \"done\";\n\t\t\tthis.endEvent.reject(error);\n\t\t}\n\t}\n\n\tprivate dispatch() {\n\t\twhile (this.working) {\n\t\t\tconst value = this.results.get(this.nextToDeliver);\n\t\t\tif (value === undefined) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tthis.results.delete(this.nextToDeliver);\n\t\t\tassert(\n\t\t\t\tvalue.length <= this.payloadSize,\n\t\t\t\t0x1d9 /* \"addRequestCore() should break into smaller chunks\" */,\n\t\t\t);\n\t\t\tthis.nextToDeliver += value.length;\n\t\t\tthis.responseCallback(value);\n\t\t}\n\n\t\t// Account for cancellation - state might be not in consistent state on cancelling operation\n\t\tif (this.working) {\n\t\t\tif (this.requestsInFlight === 0) {\n\t\t\t\t// we should have dispatched everything, no matter whether we knew about the end or not.\n\t\t\t\t// see comment in addRequestCore() around throwing away chunk if it's above this.to\n\t\t\t\tassert(\n\t\t\t\t\tthis.results.size === 0,\n\t\t\t\t\t0x107 /* \"ending dispatch with remaining results to be sent\" */,\n\t\t\t\t);\n\t\t\t\tthis.done();\n\t\t\t} else if (this.to !== undefined && this.nextToDeliver >= this.to) {\n\t\t\t\t// Learned about the end and dispatched all the ops up to it.\n\t\t\t\t// Ignore all the in-flight requests above boundary - unblock caller sooner.\n\t\t\t\tassert(\n\t\t\t\t\t!this.knewTo,\n\t\t\t\t\t0x108 /* \"ending results dispatch but knew in advance about more requests\" */,\n\t\t\t\t);\n\t\t\t\tthis.done();\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate getNextChunk() {\n\t\tif (!this.working) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tconst from = this.latestRequested;\n\t\tif (this.to !== undefined) {\n\t\t\tif (this.to <= from) {\n\t\t\t\treturn undefined;\n\t\t\t}\n\t\t}\n\n\t\t// this.latestRequested\n\t\t// inclusive on the right side! Exclusive on the left.\n\t\tthis.latestRequested += this.payloadSize;\n\n\t\tif (this.to !== undefined) {\n\t\t\tthis.latestRequested = Math.min(this.to, this.latestRequested);\n\t\t}\n\n\t\tassert(from < this.latestRequested, 0x109 /* \"unexpected next chunk position\" */);\n\n\t\treturn { from, to: this.latestRequested };\n\t}\n\n\tprivate addRequest() {\n\t\tconst chunk = this.getNextChunk();\n\t\tif (chunk === undefined) {\n\t\t\treturn;\n\t\t}\n\t\tthis.addRequestCore(chunk.from, chunk.to).catch(this.fail.bind(this));\n\t}\n\n\tprivate async addRequestCore(fromArg: number, toArg: number) {\n\t\tassert(this.working, 0x10a /* \"cannot add parallel request while not working\" */);\n\n\t\tlet from = fromArg;\n\t\tlet to = toArg;\n\n\t\t// to & from are exclusive\n\t\tthis.requestsInFlight++;\n\t\twhile (this.working) {\n\t\t\tconst requestedLength = to - from;\n\t\t\tassert(requestedLength > 0, 0x10b /* \"invalid parallel request range\" */);\n\n\t\t\t// We should not be wasting time asking for something useless.\n\t\t\tif (this.to !== undefined) {\n\t\t\t\tassert(from < this.to, 0x10c /* \"invalid parallel request start point\" */);\n\t\t\t\tassert(to <= this.to, 0x10d /* \"invalid parallel request end point\" */);\n\t\t\t}\n\n\t\t\tthis.requests++;\n\n\t\t\tconst promise = this.requestCallback(\n\t\t\t\tthis.requests,\n\t\t\t\tfrom,\n\t\t\t\tto,\n\t\t\t\tthis.to !== undefined,\n\t\t\t\t{},\n\t\t\t);\n\n\t\t\t// dispatch any prior received data\n\t\t\tthis.dispatch();\n\n\t\t\tconst { payload, cancel, partial } = await promise;\n\n\t\t\tif (cancel) {\n\t\t\t\tthis.cancel();\n\t\t\t}\n\n\t\t\tif (this.to !== undefined && from >= this.to) {\n\t\t\t\t// while we were waiting for response, we learned on what is the boundary\n\t\t\t\t// We can get here (with actual result!) if situation changed while this request was in\n\t\t\t\t// flight, i.e. the end was extended over what we learn in some other request\n\t\t\t\t// While it's useful not to throw this result, this is very corner cases and makes logic\n\t\t\t\t// (including consistency checks) much harder to write correctly.\n\t\t\t\t// So for now, we are throwing this result out the window.\n\t\t\t\tassert(\n\t\t\t\t\t!this.knewTo,\n\t\t\t\t\t0x10e /* \"should not throw result if we knew about boundary in advance\" */,\n\t\t\t\t);\n\t\t\t\t// Learn how often it happens and if it's too wasteful to throw these chunks.\n\t\t\t\t// If it pops into our view a lot, we would need to reconsider how we approach it.\n\t\t\t\t// Note that this is not visible to user other than potentially not hitting 100% of\n\t\t\t\t// what we can in perf domain.\n\t\t\t\tif (payload.length !== 0) {\n\t\t\t\t\tthis.logger.sendErrorEvent({\n\t\t\t\t\t\teventName: \"ParallelRequests_GotExtra\",\n\t\t\t\t\t\tfrom,\n\t\t\t\t\t\tto,\n\t\t\t\t\t\tend: this.to,\n\t\t\t\t\t\tlength: payload.length,\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tif (this.working) {\n\t\t\t\tconst fromOrig = from;\n\t\t\t\tconst length = payload.length;\n\t\t\t\tlet fullChunk = requestedLength <= length; // we can possible get more than we asked.\n\n\t\t\t\tif (length !== 0) {\n\t\t\t\t\t// We can get more than we asked for!\n\t\t\t\t\t// This can screw up logic in dispatch!\n\t\t\t\t\t// So push only batch size, and keep the rest for later - if conditions are favorable, we\n\t\t\t\t\t// will be able to use it. If not (parallel request overlapping these ops), it's easier to\n\t\t\t\t\t// discard them and wait for another (overlapping) request to come in later.\n\t\t\t\t\tif (requestedLength < length) {\n\t\t\t\t\t\t// This is error in a sense that it's not expected and likely points bug in other layer.\n\t\t\t\t\t\t// This layer copes with this situation just fine.\n\t\t\t\t\t\tthis.logger.sendTelemetryEvent({\n\t\t\t\t\t\t\teventName: \"ParallelRequests_Over\",\n\t\t\t\t\t\t\tfrom,\n\t\t\t\t\t\t\tto,\n\t\t\t\t\t\t\tlength,\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t\tconst data = payload.splice(0, requestedLength);\n\t\t\t\t\tthis.results.set(from, data);\n\t\t\t\t\tfrom += data.length;\n\t\t\t\t} else {\n\t\t\t\t\t// 1. empty (partial) chunks should not be returned by various caching / adapter layers -\n\t\t\t\t\t// they should fall back to next layer. This might be important invariant to hold to ensure\n\t\t\t\t\t// that we are less likely have bugs where such layer would keep returning empty partial\n\t\t\t\t\t// result on each call.\n\t\t\t\t\t// 2. Current invariant is that callback does retries until it gets something,\n\t\t\t\t\t// with the goal of failing if zero data is retrieved in given amount of time.\n\t\t\t\t\t// This is very specific property of storage / ops, so this logic is not here, but given only\n\t\t\t\t\t// one user of this class, we assert that to catch issues earlier.\n\t\t\t\t\t// These invariant can be relaxed if needed.\n\t\t\t\t\tassert(\n\t\t\t\t\t\t!partial,\n\t\t\t\t\t\t0x10f /* \"empty/partial chunks should not be returned by caching\" */,\n\t\t\t\t\t);\n\t\t\t\t\tassert(\n\t\t\t\t\t\t!this.knewTo,\n\t\t\t\t\t\t0x110 /* \"callback should retry until valid fetch before it learns new boundary\" */,\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\tif (!partial && !fullChunk) {\n\t\t\t\t\tif (!this.knewTo) {\n\t\t\t\t\t\tif (this.to === undefined || this.to > from) {\n\t\t\t\t\t\t\t// The END\n\t\t\t\t\t\t\tthis.to = from;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\t// We know that there are more items to be retrieved\n\t\t\t\t\t// Can we get partial chunk? Ideally storage indicates that's not a full chunk\n\t\t\t\t\t// Note that it's possible that not all ops hit storage yet.\n\t\t\t\t\t// We will come back to request more, and if we can't get any more ops soon, it's\n\t\t\t\t\t// catastrophic failure (see comment above on responsibility of callback to return something)\n\t\t\t\t\t// This layer will just keep trying until it gets full set.\n\t\t\t\t\tthis.logger.sendPerformanceEvent({\n\t\t\t\t\t\teventName: \"ParallelRequests_Partial\",\n\t\t\t\t\t\tfrom: fromOrig,\n\t\t\t\t\t\tto,\n\t\t\t\t\t\tlength,\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\tif (to === this.latestRequested) {\n\t\t\t\t\t// we can go after full chunk at the end if we received partial chunk, or more than asked\n\t\t\t\t\t// Also if we got more than we asked to, we can actually use those ops!\n\t\t\t\t\twhile (payload.length !== 0) {\n\t\t\t\t\t\tconst data = payload.splice(0, requestedLength);\n\t\t\t\t\t\tthis.results.set(from, data);\n\t\t\t\t\t\tfrom += data.length;\n\t\t\t\t\t}\n\n\t\t\t\t\tthis.latestRequested = from;\n\t\t\t\t\tfullChunk = true;\n\t\t\t\t}\n\n\t\t\t\tif (fullChunk) {\n\t\t\t\t\tconst chunk = this.getNextChunk();\n\t\t\t\t\tif (chunk === undefined) {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tfrom = chunk.from;\n\t\t\t\t\tto = chunk.to;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tthis.requestsInFlight--;\n\t\tthis.dispatch();\n\t}\n}\n\n/**\n * Helper queue class to allow async push / pull\n * It's essentially a pipe allowing multiple writers, and single reader\n * @public\n */\nexport class Queue<T> implements IStream<T> {\n\tprivate readonly queue: Promise<IStreamResult<T>>[] = [];\n\tprivate deferred: Deferred<IStreamResult<T>> | undefined;\n\tprivate done = false;\n\n\tpublic pushValue(value: T) {\n\t\tthis.pushCore(Promise.resolve({ done: false, value }));\n\t}\n\n\tpublic pushError(error: any) {\n\t\tthis.pushCore(Promise.reject(error));\n\t\tthis.done = true;\n\t}\n\n\tpublic pushDone() {\n\t\tthis.pushCore(Promise.resolve({ done: true }));\n\t\tthis.done = true;\n\t}\n\n\tprotected pushCore(value: Promise<IStreamResult<T>>) {\n\t\tassert(!this.done, 0x112 /* \"cannot push onto queue if done\" */);\n\t\tif (this.deferred) {\n\t\t\tassert(this.queue.length === 0, 0x113 /* \"deferred queue should be empty\" */);\n\t\t\tthis.deferred.resolve(value);\n\t\t\tthis.deferred = undefined;\n\t\t} else {\n\t\t\tthis.queue.push(value);\n\t\t}\n\t}\n\n\tpublic async read(): Promise<IStreamResult<T>> {\n\t\tassert(this.deferred === undefined, 0x114 /* \"cannot pop if deferred\" */);\n\t\tconst value = this.queue.shift();\n\t\tif (value !== undefined) {\n\t\t\treturn value;\n\t\t}\n\t\tassert(!this.done, 0x115 /* \"queue should not be done during pop\" */);\n\t\tthis.deferred = new Deferred<IStreamResult<T>>();\n\t\treturn this.deferred.promise;\n\t}\n}\n\nconst waitForOnline = async (): Promise<void> => {\n\t// Only wait if we have a strong signal that we're offline - otherwise assume we're online.\n\tif (globalThis.navigator?.onLine === false && globalThis.addEventListener !== undefined) {\n\t\treturn new Promise<void>((resolve) => {\n\t\t\tconst resolveAndRemoveListener = () => {\n\t\t\t\tresolve();\n\t\t\t\tglobalThis.removeEventListener(\"online\", resolveAndRemoveListener);\n\t\t\t};\n\t\t\tglobalThis.addEventListener(\"online\", resolveAndRemoveListener);\n\t\t});\n\t}\n};\n\n/**\n * Retrieve single batch of ops\n * @param request - request index\n * @param from - inclusive boundary\n * @param to - exclusive boundary\n * @param telemetryEvent - telemetry event used to track consecutive batch of requests\n * @param strongTo - tells if ops in range from...to have to be there and have to be retrieved.\n * If false, returning less ops would mean we reached end of file.\n * @param logger - logger object to use to log progress & errors\n * @param signal - cancelation signal\n * @param scenarioName - reason for fetching ops\n * @returns An object with resulting ops and cancellation / partial result flags\n */\nasync function getSingleOpBatch(\n\tget: (telemetryProps: ITelemetryProperties) => Promise<IDeltasFetchResult>,\n\tprops: ITelemetryProperties,\n\tstrongTo: boolean,\n\tlogger: ITelemetryLoggerExt,\n\tsignal?: AbortSignal,\n\tscenarioName?: string,\n): Promise<{ partial: boolean; cancel: boolean; payload: ISequencedDocumentMessage[] }> {\n\tlet lastSuccessTime: number | undefined;\n\tlet totalRetryAfterTime = 0;\n\tlet telemetryEvent: PerformanceEvent | undefined;\n\tlet retry: number = 0;\n\tconst nothing = { partial: false, cancel: true, payload: [] };\n\tlet waitStartTime: number = 0;\n\n\twhile (signal?.aborted !== true) {\n\t\tretry++;\n\t\tlet delay = Math.min(MaxFetchDelayInMs, MissingFetchDelayInMs * Math.pow(2, retry));\n\t\tconst startTime = performance.now();\n\n\t\ttry {\n\t\t\t// Issue async request for deltas\n\t\t\tconst { messages, partialResult } = await get(\n\t\t\t\t{ ...props, retry } /* telemetry props */,\n\t\t\t);\n\n\t\t\t// If we got messages back, return them. Return regardless of whether we got messages back if we didn't\n\t\t\t// specify a \"to\", since we don't have an expectation of how many to receive.\n\t\t\tif (messages.length !== 0 || !strongTo) {\n\t\t\t\t// Report this event if we waited to fetch ops due to being offline or throttling.\n\t\t\t\ttelemetryEvent?.end({\n\t\t\t\t\tduration: totalRetryAfterTime,\n\t\t\t\t\t...props,\n\t\t\t\t\treason: scenarioName,\n\t\t\t\t});\n\t\t\t\treturn { payload: messages, cancel: false, partial: partialResult };\n\t\t\t}\n\n\t\t\t// Otherwise, the storage gave us back an empty set of ops but we were expecting a non-empty set.\n\n\t\t\tif (lastSuccessTime === undefined) {\n\t\t\t\t// Take timestamp of the first time server responded successfully, even though it wasn't with the ops we asked for.\n\t\t\t\t// If we keep getting empty responses we'll eventually fail out below.\n\t\t\t\tlastSuccessTime = performance.now();\n\t\t\t} else if (performance.now() - lastSuccessTime > 30000) {\n\t\t\t\t// If we are connected and receiving proper responses from server, but can't get any ops back,\n\t\t\t\t// then give up after some time. This likely indicates the issue with ordering service not flushing\n\t\t\t\t// ops to storage quick enough, and possibly waiting for summaries, while summarizer can't get\n\t\t\t\t// current as it can't get ops.\n\t\t\t\tthrow createGenericNetworkError(\n\t\t\t\t\t// pre-0.58 error message: failedToRetrieveOpsFromStorage:TooManyRetries\n\t\t\t\t\t\"Failed to retrieve ops from storage (Too Many Retries)\",\n\t\t\t\t\t{ canRetry: false },\n\t\t\t\t\t{\n\t\t\t\t\t\tretry,\n\t\t\t\t\t\tdriverVersion,\n\t\t\t\t\t\t...props,\n\t\t\t\t\t},\n\t\t\t\t);\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tconst canRetry = canRetryOnError(error);\n\n\t\t\tconst retryAfter = getRetryDelayFromError(error);\n\n\t\t\t// This will log to error table only if the error is non-retryable\n\t\t\tlogNetworkFailure(\n\t\t\t\tlogger,\n\t\t\t\t{\n\t\t\t\t\teventName: \"GetDeltas_Error\",\n\t\t\t\t\t...props,\n\t\t\t\t\tretry,\n\t\t\t\t\tduration: performance.now() - startTime,\n\t\t\t\t\tretryAfter,\n\t\t\t\t\treason: scenarioName,\n\t\t\t\t},\n\t\t\t\terror,\n\t\t\t);\n\n\t\t\tif (!canRetry) {\n\t\t\t\t// It's game over scenario.\n\t\t\t\tthrow error;\n\t\t\t}\n\n\t\t\tif (retryAfter !== undefined) {\n\t\t\t\t// If the error told us to wait, then we will wait for that specific amount rather than the default.\n\t\t\t\tdelay = retryAfter;\n\t\t\t}\n\t\t}\n\n\t\tif (telemetryEvent === undefined) {\n\t\t\twaitStartTime = performance.now();\n\t\t\ttelemetryEvent = PerformanceEvent.start(logger, {\n\t\t\t\teventName: \"GetDeltasWaitTime\",\n\t\t\t});\n\t\t}\n\n\t\t// If we get here something has gone wrong - either got an unexpected empty set of messages back or a real error.\n\t\t// Either way we will wait a little bit before retrying.\n\t\tawait new Promise<void>((resolve) => {\n\t\t\tsetTimeout(resolve, delay);\n\t\t});\n\n\t\t// If we believe we're offline, we assume there's no point in trying until we at least think we're online.\n\t\t// NOTE: This isn't strictly true for drivers that don't require network (e.g. local driver). Really this logic\n\t\t// should probably live in the driver.\n\t\tawait waitForOnline();\n\t\ttotalRetryAfterTime += performance.now() - waitStartTime;\n\t}\n\n\treturn nothing;\n}\n\n/**\n * Request ops from storage\n * @param get - Getter callback to get individual batches\n * @param concurrency - Number of concurrent requests to make\n * @param fromTotal - starting sequence number to fetch (inclusive)\n * @param toTotal - max (exclusive) sequence number to fetch\n * @param payloadSize - Payload size\n * @param logger - Logger to log progress and errors\n * @param signal - Cancelation signal\n * @param scenarioName - Reason for fetching ops\n * @returns Messages fetched\n * @public\n */\nexport function requestOps(\n\tget: (\n\t\tfrom: number,\n\t\tto: number,\n\t\ttelemetryProps: ITelemetryProperties,\n\t) => Promise<IDeltasFetchResult>,\n\tconcurrency: number,\n\tfromTotal: number,\n\ttoTotal: number | undefined,\n\tpayloadSize: number,\n\tlogger: ITelemetryLoggerExt,\n\tsignal?: AbortSignal,\n\tscenarioName?: string,\n): IStream<ISequencedDocumentMessage[]> {\n\tlet requests = 0;\n\tlet lastFetch: number | undefined;\n\tlet length = 0;\n\tconst queue = new Queue<ISequencedDocumentMessage[]>();\n\n\tconst propsTotal: ITelemetryProperties = {\n\t\tfromTotal,\n\t\ttoTotal,\n\t};\n\n\tconst telemetryEvent = PerformanceEvent.start(logger, {\n\t\teventName: \"GetDeltas\",\n\t\t...propsTotal,\n\t\treason: scenarioName,\n\t});\n\n\tconst manager = new ParallelRequests<ISequencedDocumentMessage>(\n\t\tfromTotal,\n\t\ttoTotal,\n\t\tpayloadSize,\n\t\tlogger,\n\t\tasync (\n\t\t\trequest: number,\n\t\t\tfrom: number,\n\t\t\tto: number,\n\t\t\tstrongTo: boolean,\n\t\t\tpropsPerRequest: ITelemetryProperties,\n\t\t) => {\n\t\t\trequests++;\n\t\t\treturn getSingleOpBatch(\n\t\t\t\tasync (propsAll) => get(from, to, propsAll),\n\t\t\t\t{ request, from, to, ...propsTotal, ...propsPerRequest },\n\t\t\t\tstrongTo,\n\t\t\t\tlogger,\n\t\t\t\tsignal,\n\t\t\t\tscenarioName,\n\t\t\t);\n\t\t},\n\t\t(deltas: ISequencedDocumentMessage[]) => {\n\t\t\t// Assert continuing and right start.\n\t\t\tif (lastFetch === undefined) {\n\t\t\t\tassert(deltas[0].sequenceNumber === fromTotal, 0x26d /* \"wrong start\" */);\n\t\t\t} else {\n\t\t\t\tassert(deltas[0].sequenceNumber === lastFetch + 1, 0x26e /* \"wrong start\" */);\n\t\t\t}\n\t\t\tlastFetch = deltas[deltas.length - 1].sequenceNumber;\n\t\t\tassert(\n\t\t\t\tlastFetch - deltas[0].sequenceNumber + 1 === deltas.length,\n\t\t\t\t0x26f /* \"continuous and no duplicates\" */,\n\t\t\t);\n\t\t\tlength += deltas.length;\n\t\t\tqueue.pushValue(deltas);\n\t\t},\n\t);\n\n\t// Implement faster cancellation. getSingleOpBatch() checks signal, but only in between\n\t// waits (up to 10 seconds) and fetches (can take infinite amount of time).\n\t// While every such case should be improved and take into account signal (and thus cancel immediately),\n\t// it is beneficial to have catch-all\n\tconst listener = (event: Event) => {\n\t\tmanager.cancel();\n\t};\n\tif (signal !== undefined) {\n\t\tsignal.addEventListener(\"abort\", listener);\n\t}\n\n\tmanager\n\t\t.run(concurrency)\n\t\t.finally(() => {\n\t\t\tif (signal !== undefined) {\n\t\t\t\tsignal.removeEventListener(\"abort\", listener);\n\t\t\t}\n\t\t})\n\t\t.then(() => {\n\t\t\tconst props = {\n\t\t\t\tlastFetch,\n\t\t\t\tlength,\n\t\t\t\trequests,\n\t\t\t};\n\t\t\tif (manager.canceled) {\n\t\t\t\ttelemetryEvent.cancel({ ...props, error: \"ops request cancelled by client\" });\n\t\t\t} else {\n\t\t\t\tassert(\n\t\t\t\t\ttoTotal === undefined || (lastFetch !== undefined && lastFetch >= toTotal - 1),\n\t\t\t\t\t0x270 /* \"All requested ops fetched\" */,\n\t\t\t\t);\n\t\t\t\ttelemetryEvent.end(props);\n\t\t\t}\n\t\t\tqueue.pushDone();\n\t\t})\n\t\t.catch((error) => {\n\t\t\ttelemetryEvent.cancel(\n\t\t\t\t{\n\t\t\t\t\tlastFetch,\n\t\t\t\t\tlength,\n\t\t\t\t\trequests,\n\t\t\t\t},\n\t\t\t\terror,\n\t\t\t);\n\t\t\tqueue.pushError(error);\n\t\t});\n\n\treturn queue;\n}\n\n/**\n * @public\n */\nexport const emptyMessageStream: IStream<ISequencedDocumentMessage[]> = {\n\tread: async () => {\n\t\treturn { done: true };\n\t},\n};\n\n/**\n * @public\n */\nexport function streamFromMessages(\n\tmessagesArg: Promise<ISequencedDocumentMessage[]>,\n): IStream<ISequencedDocumentMessage[]> {\n\tlet messages: Promise<ISequencedDocumentMessage[]> | undefined = messagesArg;\n\treturn {\n\t\tread: async () => {\n\t\t\tif (messages === undefined) {\n\t\t\t\treturn { done: true };\n\t\t\t}\n\t\t\tconst value = await messages;\n\t\t\tmessages = undefined;\n\t\t\treturn value.length === 0 ? { done: true } : { done: false, value };\n\t\t},\n\t};\n}\n\n/**\n * @public\n */\nexport function streamObserver<T>(\n\tstream: IStream<T>,\n\thandler: (value: IStreamResult<T>) => void,\n): IStream<T> {\n\treturn {\n\t\tread: async () => {\n\t\t\tconst value = await stream.read();\n\t\t\thandler(value);\n\t\t\treturn value;\n\t\t},\n\t};\n}\n"]}
1
+ {"version":3,"file":"parallelRequests.js","sourceRoot":"","sources":["../src/parallelRequests.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\nimport { performance } from \"@fluid-internal/client-utils\";\nimport { ITelemetryProperties } from \"@fluidframework/core-interfaces\";\nimport { assert, Deferred } from \"@fluidframework/core-utils\";\nimport { ITelemetryLoggerExt, PerformanceEvent } from \"@fluidframework/telemetry-utils\";\nimport { ISequencedDocumentMessage } from \"@fluidframework/protocol-definitions\";\nimport { IDeltasFetchResult, IStream, IStreamResult } from \"@fluidframework/driver-definitions\";\nimport { getRetryDelayFromError, canRetryOnError, createGenericNetworkError } from \"./network\";\nimport { logNetworkFailure } from \"./networkUtils\";\n// For now, this package is versioned and released in unison with the specific drivers\nimport { pkgVersion as driverVersion } from \"./packageVersion\";\nimport { calculateMaxWaitTime } from \"./runWithRetry\";\n\n// We double this value in first try in when we calculate time to wait for in \"calculateMaxWaitTime\" function.\nconst MissingFetchDelayInMs = 50;\n\ntype WorkingState = \"working\" | \"done\" | \"canceled\";\n\n/**\n * Helper class to organize parallel fetching of data\n * It can be used to concurrently do many requests, while consuming\n * data in the right order. Take a look at UT for examples.\n * @param concurrency - level of concurrency\n * @param from - starting point of fetching data (inclusive)\n * @param to - ending point of fetching data. exclusive, or undefined if unknown\n * @param payloadSize - batch size\n * @param logger - logger to use\n * @param requestCallback - callback to request batches\n * @returns Queue that can be used to retrieve data\n * @public\n */\nexport class ParallelRequests<T> {\n\tprivate latestRequested: number;\n\tprivate nextToDeliver: number;\n\tprivate readonly results = new Map<number, T[]>();\n\tprivate workingState: WorkingState = \"working\";\n\tprivate requestsInFlight = 0;\n\tprivate readonly endEvent = new Deferred<void>();\n\tprivate requests = 0;\n\tprivate readonly knewTo: boolean;\n\n\tprivate get working() {\n\t\treturn this.workingState === \"working\";\n\t}\n\tpublic get canceled() {\n\t\treturn this.workingState === \"canceled\";\n\t}\n\n\tconstructor(\n\t\tfrom: number,\n\t\tprivate to: number | undefined,\n\t\tprivate readonly payloadSize: number,\n\t\tprivate readonly logger: ITelemetryLoggerExt,\n\t\tprivate readonly requestCallback: (\n\t\t\trequest: number,\n\t\t\tfrom: number,\n\t\t\tto: number,\n\t\t\tstrongTo: boolean,\n\t\t\tprops: ITelemetryProperties,\n\t\t) => Promise<{ partial: boolean; cancel: boolean; payload: T[] }>,\n\t\tprivate readonly responseCallback: (payload: T[]) => void,\n\t) {\n\t\tthis.latestRequested = from;\n\t\tthis.nextToDeliver = from;\n\t\tthis.knewTo = to !== undefined;\n\t}\n\n\tpublic cancel() {\n\t\tif (this.working) {\n\t\t\tthis.workingState = \"canceled\";\n\t\t\tthis.endEvent.resolve();\n\t\t}\n\t}\n\n\tpublic async run(concurrency: number) {\n\t\tassert(concurrency > 0, 0x102 /* \"invalid level of concurrency\" */);\n\t\tassert(this.working, 0x103 /* \"trying to parallel run while not working\" */);\n\n\t\tlet c = concurrency;\n\t\twhile (c > 0) {\n\t\t\tc--;\n\t\t\tthis.addRequest();\n\t\t}\n\t\tthis.dispatch(); // will recalculate and trigger this.endEvent if needed\n\t\treturn this.endEvent.promise;\n\t}\n\n\tprivate done() {\n\t\t// We should satisfy request fully.\n\t\tassert(this.to !== undefined, 0x104 /* \"undefined end point for parallel fetch\" */);\n\t\tassert(\n\t\t\tthis.nextToDeliver >= this.to,\n\t\t\t0x105 /* \"unexpected end point for parallel fetch\" */,\n\t\t);\n\t\tif (this.working) {\n\t\t\tthis.workingState = \"done\";\n\t\t\tthis.endEvent.resolve();\n\t\t}\n\t}\n\n\tprivate fail(error) {\n\t\tif (this.working) {\n\t\t\tthis.workingState = \"done\";\n\t\t\tthis.endEvent.reject(error);\n\t\t}\n\t}\n\n\tprivate dispatch() {\n\t\twhile (this.working) {\n\t\t\tconst value = this.results.get(this.nextToDeliver);\n\t\t\tif (value === undefined) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tthis.results.delete(this.nextToDeliver);\n\t\t\tassert(\n\t\t\t\tvalue.length <= this.payloadSize,\n\t\t\t\t0x1d9 /* \"addRequestCore() should break into smaller chunks\" */,\n\t\t\t);\n\t\t\tthis.nextToDeliver += value.length;\n\t\t\tthis.responseCallback(value);\n\t\t}\n\n\t\t// Account for cancellation - state might be not in consistent state on cancelling operation\n\t\tif (this.working) {\n\t\t\tif (this.requestsInFlight === 0) {\n\t\t\t\t// we should have dispatched everything, no matter whether we knew about the end or not.\n\t\t\t\t// see comment in addRequestCore() around throwing away chunk if it's above this.to\n\t\t\t\tassert(\n\t\t\t\t\tthis.results.size === 0,\n\t\t\t\t\t0x107 /* \"ending dispatch with remaining results to be sent\" */,\n\t\t\t\t);\n\t\t\t\tthis.done();\n\t\t\t} else if (this.to !== undefined && this.nextToDeliver >= this.to) {\n\t\t\t\t// Learned about the end and dispatched all the ops up to it.\n\t\t\t\t// Ignore all the in-flight requests above boundary - unblock caller sooner.\n\t\t\t\tassert(\n\t\t\t\t\t!this.knewTo,\n\t\t\t\t\t0x108 /* \"ending results dispatch but knew in advance about more requests\" */,\n\t\t\t\t);\n\t\t\t\tthis.done();\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate getNextChunk() {\n\t\tif (!this.working) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tconst from = this.latestRequested;\n\t\tif (this.to !== undefined) {\n\t\t\tif (this.to <= from) {\n\t\t\t\treturn undefined;\n\t\t\t}\n\t\t}\n\n\t\t// this.latestRequested\n\t\t// inclusive on the right side! Exclusive on the left.\n\t\tthis.latestRequested += this.payloadSize;\n\n\t\tif (this.to !== undefined) {\n\t\t\tthis.latestRequested = Math.min(this.to, this.latestRequested);\n\t\t}\n\n\t\tassert(from < this.latestRequested, 0x109 /* \"unexpected next chunk position\" */);\n\n\t\treturn { from, to: this.latestRequested };\n\t}\n\n\tprivate addRequest() {\n\t\tconst chunk = this.getNextChunk();\n\t\tif (chunk === undefined) {\n\t\t\treturn;\n\t\t}\n\t\tthis.addRequestCore(chunk.from, chunk.to).catch(this.fail.bind(this));\n\t}\n\n\tprivate async addRequestCore(fromArg: number, toArg: number) {\n\t\tassert(this.working, 0x10a /* \"cannot add parallel request while not working\" */);\n\n\t\tlet from = fromArg;\n\t\tlet to = toArg;\n\n\t\t// to & from are exclusive\n\t\tthis.requestsInFlight++;\n\t\twhile (this.working) {\n\t\t\tconst requestedLength = to - from;\n\t\t\tassert(requestedLength > 0, 0x10b /* \"invalid parallel request range\" */);\n\n\t\t\t// We should not be wasting time asking for something useless.\n\t\t\tif (this.to !== undefined) {\n\t\t\t\tassert(from < this.to, 0x10c /* \"invalid parallel request start point\" */);\n\t\t\t\tassert(to <= this.to, 0x10d /* \"invalid parallel request end point\" */);\n\t\t\t}\n\n\t\t\tthis.requests++;\n\n\t\t\tconst promise = this.requestCallback(\n\t\t\t\tthis.requests,\n\t\t\t\tfrom,\n\t\t\t\tto,\n\t\t\t\tthis.to !== undefined,\n\t\t\t\t{},\n\t\t\t);\n\n\t\t\t// dispatch any prior received data\n\t\t\tthis.dispatch();\n\n\t\t\tconst { payload, cancel, partial } = await promise;\n\n\t\t\tif (cancel) {\n\t\t\t\tthis.cancel();\n\t\t\t}\n\n\t\t\tif (this.to !== undefined && from >= this.to) {\n\t\t\t\t// while we were waiting for response, we learned on what is the boundary\n\t\t\t\t// We can get here (with actual result!) if situation changed while this request was in\n\t\t\t\t// flight, i.e. the end was extended over what we learn in some other request\n\t\t\t\t// While it's useful not to throw this result, this is very corner cases and makes logic\n\t\t\t\t// (including consistency checks) much harder to write correctly.\n\t\t\t\t// So for now, we are throwing this result out the window.\n\t\t\t\tassert(\n\t\t\t\t\t!this.knewTo,\n\t\t\t\t\t0x10e /* \"should not throw result if we knew about boundary in advance\" */,\n\t\t\t\t);\n\t\t\t\t// Learn how often it happens and if it's too wasteful to throw these chunks.\n\t\t\t\t// If it pops into our view a lot, we would need to reconsider how we approach it.\n\t\t\t\t// Note that this is not visible to user other than potentially not hitting 100% of\n\t\t\t\t// what we can in perf domain.\n\t\t\t\tif (payload.length !== 0) {\n\t\t\t\t\tthis.logger.sendErrorEvent({\n\t\t\t\t\t\teventName: \"ParallelRequests_GotExtra\",\n\t\t\t\t\t\tfrom,\n\t\t\t\t\t\tto,\n\t\t\t\t\t\tend: this.to,\n\t\t\t\t\t\tlength: payload.length,\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tif (this.working) {\n\t\t\t\tconst fromOrig = from;\n\t\t\t\tconst length = payload.length;\n\t\t\t\tlet fullChunk = requestedLength <= length; // we can possible get more than we asked.\n\n\t\t\t\tif (length !== 0) {\n\t\t\t\t\t// We can get more than we asked for!\n\t\t\t\t\t// This can screw up logic in dispatch!\n\t\t\t\t\t// So push only batch size, and keep the rest for later - if conditions are favorable, we\n\t\t\t\t\t// will be able to use it. If not (parallel request overlapping these ops), it's easier to\n\t\t\t\t\t// discard them and wait for another (overlapping) request to come in later.\n\t\t\t\t\tif (requestedLength < length) {\n\t\t\t\t\t\t// This is error in a sense that it's not expected and likely points bug in other layer.\n\t\t\t\t\t\t// This layer copes with this situation just fine.\n\t\t\t\t\t\tthis.logger.sendTelemetryEvent({\n\t\t\t\t\t\t\teventName: \"ParallelRequests_Over\",\n\t\t\t\t\t\t\tfrom,\n\t\t\t\t\t\t\tto,\n\t\t\t\t\t\t\tlength,\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t\tconst data = payload.splice(0, requestedLength);\n\t\t\t\t\tthis.results.set(from, data);\n\t\t\t\t\tfrom += data.length;\n\t\t\t\t} else {\n\t\t\t\t\t// 1. empty (partial) chunks should not be returned by various caching / adapter layers -\n\t\t\t\t\t// they should fall back to next layer. This might be important invariant to hold to ensure\n\t\t\t\t\t// that we are less likely have bugs where such layer would keep returning empty partial\n\t\t\t\t\t// result on each call.\n\t\t\t\t\t// 2. Current invariant is that callback does retries until it gets something,\n\t\t\t\t\t// with the goal of failing if zero data is retrieved in given amount of time.\n\t\t\t\t\t// This is very specific property of storage / ops, so this logic is not here, but given only\n\t\t\t\t\t// one user of this class, we assert that to catch issues earlier.\n\t\t\t\t\t// These invariant can be relaxed if needed.\n\t\t\t\t\tassert(\n\t\t\t\t\t\t!partial,\n\t\t\t\t\t\t0x10f /* \"empty/partial chunks should not be returned by caching\" */,\n\t\t\t\t\t);\n\t\t\t\t\tassert(\n\t\t\t\t\t\t!this.knewTo,\n\t\t\t\t\t\t0x110 /* \"callback should retry until valid fetch before it learns new boundary\" */,\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\tif (!partial && !fullChunk) {\n\t\t\t\t\tif (!this.knewTo) {\n\t\t\t\t\t\tif (this.to === undefined || this.to > from) {\n\t\t\t\t\t\t\t// The END\n\t\t\t\t\t\t\tthis.to = from;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\t// We know that there are more items to be retrieved\n\t\t\t\t\t// Can we get partial chunk? Ideally storage indicates that's not a full chunk\n\t\t\t\t\t// Note that it's possible that not all ops hit storage yet.\n\t\t\t\t\t// We will come back to request more, and if we can't get any more ops soon, it's\n\t\t\t\t\t// catastrophic failure (see comment above on responsibility of callback to return something)\n\t\t\t\t\t// This layer will just keep trying until it gets full set.\n\t\t\t\t\tthis.logger.sendPerformanceEvent({\n\t\t\t\t\t\teventName: \"ParallelRequests_Partial\",\n\t\t\t\t\t\tfrom: fromOrig,\n\t\t\t\t\t\tto,\n\t\t\t\t\t\tlength,\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\tif (to === this.latestRequested) {\n\t\t\t\t\t// we can go after full chunk at the end if we received partial chunk, or more than asked\n\t\t\t\t\t// Also if we got more than we asked to, we can actually use those ops!\n\t\t\t\t\twhile (payload.length !== 0) {\n\t\t\t\t\t\tconst data = payload.splice(0, requestedLength);\n\t\t\t\t\t\tthis.results.set(from, data);\n\t\t\t\t\t\tfrom += data.length;\n\t\t\t\t\t}\n\n\t\t\t\t\tthis.latestRequested = from;\n\t\t\t\t\tfullChunk = true;\n\t\t\t\t}\n\n\t\t\t\tif (fullChunk) {\n\t\t\t\t\tconst chunk = this.getNextChunk();\n\t\t\t\t\tif (chunk === undefined) {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tfrom = chunk.from;\n\t\t\t\t\tto = chunk.to;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tthis.requestsInFlight--;\n\t\tthis.dispatch();\n\t}\n}\n\n/**\n * Helper queue class to allow async push / pull\n * It's essentially a pipe allowing multiple writers, and single reader\n * @public\n */\nexport class Queue<T> implements IStream<T> {\n\tprivate readonly queue: Promise<IStreamResult<T>>[] = [];\n\tprivate deferred: Deferred<IStreamResult<T>> | undefined;\n\tprivate done = false;\n\n\tpublic pushValue(value: T) {\n\t\tthis.pushCore(Promise.resolve({ done: false, value }));\n\t}\n\n\tpublic pushError(error: any) {\n\t\tthis.pushCore(Promise.reject(error));\n\t\tthis.done = true;\n\t}\n\n\tpublic pushDone() {\n\t\tthis.pushCore(Promise.resolve({ done: true }));\n\t\tthis.done = true;\n\t}\n\n\tprotected pushCore(value: Promise<IStreamResult<T>>) {\n\t\tassert(!this.done, 0x112 /* \"cannot push onto queue if done\" */);\n\t\tif (this.deferred) {\n\t\t\tassert(this.queue.length === 0, 0x113 /* \"deferred queue should be empty\" */);\n\t\t\tthis.deferred.resolve(value);\n\t\t\tthis.deferred = undefined;\n\t\t} else {\n\t\t\tthis.queue.push(value);\n\t\t}\n\t}\n\n\tpublic async read(): Promise<IStreamResult<T>> {\n\t\tassert(this.deferred === undefined, 0x114 /* \"cannot pop if deferred\" */);\n\t\tconst value = this.queue.shift();\n\t\tif (value !== undefined) {\n\t\t\treturn value;\n\t\t}\n\t\tassert(!this.done, 0x115 /* \"queue should not be done during pop\" */);\n\t\tthis.deferred = new Deferred<IStreamResult<T>>();\n\t\treturn this.deferred.promise;\n\t}\n}\n\nconst waitForOnline = async (): Promise<void> => {\n\t// Only wait if we have a strong signal that we're offline - otherwise assume we're online.\n\tif (globalThis.navigator?.onLine === false && globalThis.addEventListener !== undefined) {\n\t\treturn new Promise<void>((resolve) => {\n\t\t\tconst resolveAndRemoveListener = () => {\n\t\t\t\tresolve();\n\t\t\t\tglobalThis.removeEventListener(\"online\", resolveAndRemoveListener);\n\t\t\t};\n\t\t\tglobalThis.addEventListener(\"online\", resolveAndRemoveListener);\n\t\t});\n\t}\n};\n\n/**\n * Retrieve single batch of ops\n * @param request - request index\n * @param from - inclusive boundary\n * @param to - exclusive boundary\n * @param telemetryEvent - telemetry event used to track consecutive batch of requests\n * @param strongTo - tells if ops in range from...to have to be there and have to be retrieved.\n * If false, returning less ops would mean we reached end of file.\n * @param logger - logger object to use to log progress & errors\n * @param signal - cancelation signal\n * @param scenarioName - reason for fetching ops\n * @returns An object with resulting ops and cancellation / partial result flags\n */\nasync function getSingleOpBatch(\n\tget: (telemetryProps: ITelemetryProperties) => Promise<IDeltasFetchResult>,\n\tprops: ITelemetryProperties,\n\tstrongTo: boolean,\n\tlogger: ITelemetryLoggerExt,\n\tsignal?: AbortSignal,\n\tscenarioName?: string,\n): Promise<{ partial: boolean; cancel: boolean; payload: ISequencedDocumentMessage[] }> {\n\tlet lastSuccessTime: number | undefined;\n\tlet totalRetryAfterTime = 0;\n\tlet telemetryEvent: PerformanceEvent | undefined;\n\tlet retry: number = 0;\n\tconst nothing = { partial: false, cancel: true, payload: [] };\n\tlet waitStartTime: number = 0;\n\tlet waitTime = MissingFetchDelayInMs;\n\n\twhile (signal?.aborted !== true) {\n\t\tretry++;\n\t\tlet lastError: unknown;\n\t\tconst startTime = performance.now();\n\n\t\ttry {\n\t\t\t// Issue async request for deltas\n\t\t\tconst { messages, partialResult } = await get(\n\t\t\t\t{ ...props, retry } /* telemetry props */,\n\t\t\t);\n\n\t\t\t// If we got messages back, return them. Return regardless of whether we got messages back if we didn't\n\t\t\t// specify a \"to\", since we don't have an expectation of how many to receive.\n\t\t\tif (messages.length !== 0 || !strongTo) {\n\t\t\t\t// Report this event if we waited to fetch ops due to being offline or throttling.\n\t\t\t\ttelemetryEvent?.end({\n\t\t\t\t\tduration: totalRetryAfterTime,\n\t\t\t\t\t...props,\n\t\t\t\t\treason: scenarioName,\n\t\t\t\t});\n\t\t\t\treturn { payload: messages, cancel: false, partial: partialResult };\n\t\t\t}\n\n\t\t\t// Otherwise, the storage gave us back an empty set of ops but we were expecting a non-empty set.\n\n\t\t\tif (lastSuccessTime === undefined) {\n\t\t\t\t// Take timestamp of the first time server responded successfully, even though it wasn't with the ops we asked for.\n\t\t\t\t// If we keep getting empty responses we'll eventually fail out below.\n\t\t\t\tlastSuccessTime = performance.now();\n\t\t\t} else if (performance.now() - lastSuccessTime > 30000) {\n\t\t\t\t// If we are connected and receiving proper responses from server, but can't get any ops back,\n\t\t\t\t// then give up after some time. This likely indicates the issue with ordering service not flushing\n\t\t\t\t// ops to storage quick enough, and possibly waiting for summaries, while summarizer can't get\n\t\t\t\t// current as it can't get ops.\n\t\t\t\tthrow createGenericNetworkError(\n\t\t\t\t\t// pre-0.58 error message: failedToRetrieveOpsFromStorage:TooManyRetries\n\t\t\t\t\t\"Failed to retrieve ops from storage (Too Many Retries)\",\n\t\t\t\t\t{ canRetry: false },\n\t\t\t\t\t{\n\t\t\t\t\t\tretry,\n\t\t\t\t\t\tdriverVersion,\n\t\t\t\t\t\t...props,\n\t\t\t\t\t},\n\t\t\t\t);\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tlastError = error;\n\t\t\tconst canRetry = canRetryOnError(error);\n\n\t\t\tconst retryAfter = getRetryDelayFromError(error);\n\n\t\t\t// This will log to error table only if the error is non-retryable\n\t\t\tlogNetworkFailure(\n\t\t\t\tlogger,\n\t\t\t\t{\n\t\t\t\t\teventName: \"GetDeltas_Error\",\n\t\t\t\t\t...props,\n\t\t\t\t\tretry,\n\t\t\t\t\tduration: performance.now() - startTime,\n\t\t\t\t\tretryAfter,\n\t\t\t\t\treason: scenarioName,\n\t\t\t\t},\n\t\t\t\terror,\n\t\t\t);\n\n\t\t\tif (!canRetry) {\n\t\t\t\t// It's game over scenario.\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t}\n\n\t\tif (telemetryEvent === undefined) {\n\t\t\twaitStartTime = performance.now();\n\t\t\ttelemetryEvent = PerformanceEvent.start(logger, {\n\t\t\t\teventName: \"GetDeltasWaitTime\",\n\t\t\t});\n\t\t}\n\n\t\twaitTime = calculateMaxWaitTime(waitTime, lastError);\n\n\t\t// If we get here something has gone wrong - either got an unexpected empty set of messages back or a real error.\n\t\t// Either way we will wait a little bit before retrying.\n\t\tawait new Promise<void>((resolve) => {\n\t\t\tsetTimeout(resolve, waitTime);\n\t\t});\n\n\t\t// If we believe we're offline, we assume there's no point in trying until we at least think we're online.\n\t\t// NOTE: This isn't strictly true for drivers that don't require network (e.g. local driver). Really this logic\n\t\t// should probably live in the driver.\n\t\tawait waitForOnline();\n\t\ttotalRetryAfterTime += performance.now() - waitStartTime;\n\t}\n\n\treturn nothing;\n}\n\n/**\n * Request ops from storage\n * @param get - Getter callback to get individual batches\n * @param concurrency - Number of concurrent requests to make\n * @param fromTotal - starting sequence number to fetch (inclusive)\n * @param toTotal - max (exclusive) sequence number to fetch\n * @param payloadSize - Payload size\n * @param logger - Logger to log progress and errors\n * @param signal - Cancelation signal\n * @param scenarioName - Reason for fetching ops\n * @returns Messages fetched\n * @public\n */\nexport function requestOps(\n\tget: (\n\t\tfrom: number,\n\t\tto: number,\n\t\ttelemetryProps: ITelemetryProperties,\n\t) => Promise<IDeltasFetchResult>,\n\tconcurrency: number,\n\tfromTotal: number,\n\ttoTotal: number | undefined,\n\tpayloadSize: number,\n\tlogger: ITelemetryLoggerExt,\n\tsignal?: AbortSignal,\n\tscenarioName?: string,\n): IStream<ISequencedDocumentMessage[]> {\n\tlet requests = 0;\n\tlet lastFetch: number | undefined;\n\tlet length = 0;\n\tconst queue = new Queue<ISequencedDocumentMessage[]>();\n\n\tconst propsTotal: ITelemetryProperties = {\n\t\tfromTotal,\n\t\ttoTotal,\n\t};\n\n\tconst telemetryEvent = PerformanceEvent.start(logger, {\n\t\teventName: \"GetDeltas\",\n\t\t...propsTotal,\n\t\treason: scenarioName,\n\t});\n\n\tconst manager = new ParallelRequests<ISequencedDocumentMessage>(\n\t\tfromTotal,\n\t\ttoTotal,\n\t\tpayloadSize,\n\t\tlogger,\n\t\tasync (\n\t\t\trequest: number,\n\t\t\tfrom: number,\n\t\t\tto: number,\n\t\t\tstrongTo: boolean,\n\t\t\tpropsPerRequest: ITelemetryProperties,\n\t\t) => {\n\t\t\trequests++;\n\t\t\treturn getSingleOpBatch(\n\t\t\t\tasync (propsAll) => get(from, to, propsAll),\n\t\t\t\t{ request, from, to, ...propsTotal, ...propsPerRequest },\n\t\t\t\tstrongTo,\n\t\t\t\tlogger,\n\t\t\t\tsignal,\n\t\t\t\tscenarioName,\n\t\t\t);\n\t\t},\n\t\t(deltas: ISequencedDocumentMessage[]) => {\n\t\t\t// Assert continuing and right start.\n\t\t\tif (lastFetch === undefined) {\n\t\t\t\tassert(deltas[0].sequenceNumber === fromTotal, 0x26d /* \"wrong start\" */);\n\t\t\t} else {\n\t\t\t\tassert(deltas[0].sequenceNumber === lastFetch + 1, 0x26e /* \"wrong start\" */);\n\t\t\t}\n\t\t\tlastFetch = deltas[deltas.length - 1].sequenceNumber;\n\t\t\tassert(\n\t\t\t\tlastFetch - deltas[0].sequenceNumber + 1 === deltas.length,\n\t\t\t\t0x26f /* \"continuous and no duplicates\" */,\n\t\t\t);\n\t\t\tlength += deltas.length;\n\t\t\tqueue.pushValue(deltas);\n\t\t},\n\t);\n\n\t// Implement faster cancellation. getSingleOpBatch() checks signal, but only in between\n\t// waits (up to 10 seconds) and fetches (can take infinite amount of time).\n\t// While every such case should be improved and take into account signal (and thus cancel immediately),\n\t// it is beneficial to have catch-all\n\tconst listener = (event: Event) => {\n\t\tmanager.cancel();\n\t};\n\tif (signal !== undefined) {\n\t\tsignal.addEventListener(\"abort\", listener);\n\t}\n\n\tmanager\n\t\t.run(concurrency)\n\t\t.finally(() => {\n\t\t\tif (signal !== undefined) {\n\t\t\t\tsignal.removeEventListener(\"abort\", listener);\n\t\t\t}\n\t\t})\n\t\t.then(() => {\n\t\t\tconst props = {\n\t\t\t\tlastFetch,\n\t\t\t\tlength,\n\t\t\t\trequests,\n\t\t\t};\n\t\t\tif (manager.canceled) {\n\t\t\t\ttelemetryEvent.cancel({ ...props, error: \"ops request cancelled by client\" });\n\t\t\t} else {\n\t\t\t\tassert(\n\t\t\t\t\ttoTotal === undefined || (lastFetch !== undefined && lastFetch >= toTotal - 1),\n\t\t\t\t\t0x270 /* \"All requested ops fetched\" */,\n\t\t\t\t);\n\t\t\t\ttelemetryEvent.end(props);\n\t\t\t}\n\t\t\tqueue.pushDone();\n\t\t})\n\t\t.catch((error) => {\n\t\t\ttelemetryEvent.cancel(\n\t\t\t\t{\n\t\t\t\t\tlastFetch,\n\t\t\t\t\tlength,\n\t\t\t\t\trequests,\n\t\t\t\t},\n\t\t\t\terror,\n\t\t\t);\n\t\t\tqueue.pushError(error);\n\t\t});\n\n\treturn queue;\n}\n\n/**\n * @public\n */\nexport const emptyMessageStream: IStream<ISequencedDocumentMessage[]> = {\n\tread: async () => {\n\t\treturn { done: true };\n\t},\n};\n\n/**\n * @public\n */\nexport function streamFromMessages(\n\tmessagesArg: Promise<ISequencedDocumentMessage[]>,\n): IStream<ISequencedDocumentMessage[]> {\n\tlet messages: Promise<ISequencedDocumentMessage[]> | undefined = messagesArg;\n\treturn {\n\t\tread: async () => {\n\t\t\tif (messages === undefined) {\n\t\t\t\treturn { done: true };\n\t\t\t}\n\t\t\tconst value = await messages;\n\t\t\tmessages = undefined;\n\t\t\treturn value.length === 0 ? { done: true } : { done: false, value };\n\t\t},\n\t};\n}\n\n/**\n * @public\n */\nexport function streamObserver<T>(\n\tstream: IStream<T>,\n\thandler: (value: IStreamResult<T>) => void,\n): IStream<T> {\n\treturn {\n\t\tread: async () => {\n\t\t\tconst value = await stream.read();\n\t\t\thandler(value);\n\t\t\treturn value;\n\t\t},\n\t};\n}\n"]}
@@ -39,12 +39,14 @@ export interface IProgress {
39
39
  */
40
40
  export declare function runWithRetry<T>(api: (cancel?: AbortSignal) => Promise<T>, fetchCallName: string, logger: ITelemetryLoggerExt, progress: IProgress): Promise<T>;
41
41
  /**
42
- * In case endpoint(service or socket) is not reachable, then we maybe offline or may have got some transient error
43
- * not related to endpoint, in that case we want to try at faster pace and hence the max wait is lesser 8s as compared
44
- * to when endpoint is reachable in which case it is 30s.
45
- * @param error - error based on which we decide max wait time.
46
- * @returns Max wait time.
42
+ * Calculates time to wait for after an error based on the error and wait time for previous iteration.
43
+ * In case endpoint(service or socket) is not reachable, then we maybe offline or may have got some
44
+ * transient error not related to endpoint, in that case we want to try at faster pace and hence the
45
+ * max wait is lesser 8s as compared to when endpoint is reachable in which case it is 60s.
46
+ * @param delayMs - wait time for previous iteration
47
+ * @param error - error based on which we decide wait time.
48
+ * @returns Wait time to wait for.
47
49
  * @public
48
50
  */
49
- export declare function calculateMaxWaitTime(error: unknown): number;
51
+ export declare function calculateMaxWaitTime(delayMs: number, error: unknown): number;
50
52
  //# sourceMappingURL=runWithRetry.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"runWithRetry.d.ts","sourceRoot":"","sources":["../src/runWithRetry.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,mBAAmB,EAAgB,MAAM,iCAAiC,CAAC;AAQpF;;;;GAIG;AACH,MAAM,WAAW,SAAS;IACzB;;;;;;;;;;;;;OAaG;IACH,MAAM,CAAC,EAAE,WAAW,CAAC;IAErB;;;;;;;OAOG;IACH,OAAO,CAAC,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,GAAG,IAAI,CAAC;CAC9C;AAED;;GAEG;AACH,wBAAsB,YAAY,CAAC,CAAC,EACnC,GAAG,EAAE,CAAC,MAAM,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,CAAC,CAAC,EACzC,aAAa,EAAE,MAAM,EACrB,MAAM,EAAE,mBAAmB,EAC3B,QAAQ,EAAE,SAAS,GACjB,OAAO,CAAC,CAAC,CAAC,CAuFZ;AAKD;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAI3D"}
1
+ {"version":3,"file":"runWithRetry.d.ts","sourceRoot":"","sources":["../src/runWithRetry.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,mBAAmB,EAAgB,MAAM,iCAAiC,CAAC;AAQpF;;;;GAIG;AACH,MAAM,WAAW,SAAS;IACzB;;;;;;;;;;;;;OAaG;IACH,MAAM,CAAC,EAAE,WAAW,CAAC;IAErB;;;;;;;OAOG;IACH,OAAO,CAAC,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,GAAG,IAAI,CAAC;CAC9C;AAED;;GAEG;AACH,wBAAsB,YAAY,CAAC,CAAC,EACnC,GAAG,EAAE,CAAC,MAAM,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,CAAC,CAAC,EACzC,aAAa,EAAE,MAAM,EACrB,MAAM,EAAE,mBAAmB,EAC3B,QAAQ,EAAE,SAAS,GACjB,OAAO,CAAC,CAAC,CAAC,CAsFZ;AAKD;;;;;;;;;GASG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,MAAM,CAU5E"}
@@ -18,7 +18,8 @@ const _1 = require(".");
18
18
  async function runWithRetry(api, fetchCallName, logger, progress) {
19
19
  let result;
20
20
  let success = false;
21
- let retryAfterMs = 1000; // has to be positive!
21
+ // We double this value in first try in when we calculate time to wait for in "calculateMaxWaitTime" function.
22
+ let retryAfterMs = 500; // has to be positive!
22
23
  let numRetries = 0;
23
24
  const startTime = client_utils_1.performance.now();
24
25
  let lastError;
@@ -64,10 +65,8 @@ async function runWithRetry(api, fetchCallName, logger, progress) {
64
65
  }
65
66
  numRetries++;
66
67
  lastError = err;
67
- // If the error is throttling error, then wait for the specified time before retrying.
68
- retryAfterMs =
69
- (0, network_1.getRetryDelayFromError)(err) ??
70
- Math.min(retryAfterMs * 2, calculateMaxWaitTime(err));
68
+ // Wait for the calculated time before retrying.
69
+ retryAfterMs = calculateMaxWaitTime(retryAfterMs, err);
71
70
  if (progress.onRetry) {
72
71
  progress.onRetry(retryAfterMs, err);
73
72
  }
@@ -86,20 +85,25 @@ async function runWithRetry(api, fetchCallName, logger, progress) {
86
85
  return result;
87
86
  }
88
87
  exports.runWithRetry = runWithRetry;
89
- const MaxReconnectDelayInMsWhenEndpointIsReachable = 30000;
88
+ const MaxReconnectDelayInMsWhenEndpointIsReachable = 60000;
90
89
  const MaxReconnectDelayInMsWhenEndpointIsNotReachable = 8000;
91
90
  /**
92
- * In case endpoint(service or socket) is not reachable, then we maybe offline or may have got some transient error
93
- * not related to endpoint, in that case we want to try at faster pace and hence the max wait is lesser 8s as compared
94
- * to when endpoint is reachable in which case it is 30s.
95
- * @param error - error based on which we decide max wait time.
96
- * @returns Max wait time.
91
+ * Calculates time to wait for after an error based on the error and wait time for previous iteration.
92
+ * In case endpoint(service or socket) is not reachable, then we maybe offline or may have got some
93
+ * transient error not related to endpoint, in that case we want to try at faster pace and hence the
94
+ * max wait is lesser 8s as compared to when endpoint is reachable in which case it is 60s.
95
+ * @param delayMs - wait time for previous iteration
96
+ * @param error - error based on which we decide wait time.
97
+ * @returns Wait time to wait for.
97
98
  * @public
98
99
  */
99
- function calculateMaxWaitTime(error) {
100
- return (0, telemetry_utils_1.isFluidError)(error) && error.getTelemetryProperties().endpointReached === true
100
+ function calculateMaxWaitTime(delayMs, error) {
101
+ const retryDelayFromError = (0, network_1.getRetryDelayFromError)(error);
102
+ let newDelayMs = Math.max(retryDelayFromError ?? 0, delayMs * 2);
103
+ newDelayMs = Math.min(delayMs, (0, telemetry_utils_1.isFluidError)(error) && error.getTelemetryProperties().endpointReached === true
101
104
  ? MaxReconnectDelayInMsWhenEndpointIsReachable
102
- : MaxReconnectDelayInMsWhenEndpointIsNotReachable;
105
+ : MaxReconnectDelayInMsWhenEndpointIsNotReachable);
106
+ return newDelayMs;
103
107
  }
104
108
  exports.calculateMaxWaitTime = calculateMaxWaitTime;
105
109
  //# sourceMappingURL=runWithRetry.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"runWithRetry.js","sourceRoot":"","sources":["../src/runWithRetry.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { ITelemetryLoggerExt, isFluidError } from \"@fluidframework/telemetry-utils\";\nimport { performance } from \"@fluid-internal/client-utils\";\nimport { delay } from \"@fluidframework/core-utils\";\nimport { DriverErrorTypes } from \"@fluidframework/driver-definitions\";\nimport { canRetryOnError, getRetryDelayFromError } from \"./network\";\nimport { pkgVersion } from \"./packageVersion\";\nimport { NonRetryableError } from \".\";\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 * @public\n */\nexport interface IProgress {\n\t/**\n\t * Abort signal used to cancel operation.\n\t *\n\t * @remarks Note that most of the layers do not use this signal yet. We need to change that over time.\n\t * Please consult with API documentation / implementation.\n\t * Note that number of layers may not check this signal while holding this request in a queue,\n\t * so it may take a while it takes effect. This can be improved in the future.\n\t *\n\t * The layers in question are:\n\t *\n\t * - driver (RateLimiter)\n\t *\n\t * - runWithRetry\n\t */\n\tcancel?: AbortSignal;\n\n\t/**\n\t * Called whenever api returns cancellable error and the call is going to be retried.\n\t * Any exception thrown from this call back result in cancellation of operation\n\t * and propagation of thrown exception.\n\t * @param delayInMs - delay before next retry. This value will depend on internal back-off logic,\n\t * as well as information provided by service (like 429 error asking to wait for some time before retry)\n\t * @param error - error object returned from the call.\n\t */\n\tonRetry?(delayInMs: number, error: any): void;\n}\n\n/**\n * @public\n */\nexport async function runWithRetry<T>(\n\tapi: (cancel?: AbortSignal) => Promise<T>,\n\tfetchCallName: string,\n\tlogger: ITelemetryLoggerExt,\n\tprogress: IProgress,\n): Promise<T> {\n\tlet result: T | undefined;\n\tlet success = false;\n\tlet retryAfterMs = 1000; // has to be positive!\n\tlet numRetries = 0;\n\tconst startTime = performance.now();\n\tlet lastError: any;\n\tdo {\n\t\ttry {\n\t\t\tresult = await api(progress.cancel);\n\t\t\tsuccess = true;\n\t\t} catch (err) {\n\t\t\t// If it is not retriable, then just throw the error.\n\t\t\tif (!canRetryOnError(err)) {\n\t\t\t\tlogger.sendTelemetryEvent(\n\t\t\t\t\t{\n\t\t\t\t\t\teventName: `${fetchCallName}_cancel`,\n\t\t\t\t\t\tretry: numRetries,\n\t\t\t\t\t\tduration: performance.now() - startTime,\n\t\t\t\t\t\tfetchCallName,\n\t\t\t\t\t},\n\t\t\t\t\terr,\n\t\t\t\t);\n\t\t\t\tthrow err;\n\t\t\t}\n\n\t\t\tif (progress.cancel?.aborted === true) {\n\t\t\t\tlogger.sendTelemetryEvent(\n\t\t\t\t\t{\n\t\t\t\t\t\teventName: `${fetchCallName}_runWithRetryAborted`,\n\t\t\t\t\t\tretry: numRetries,\n\t\t\t\t\t\tduration: performance.now() - startTime,\n\t\t\t\t\t\tfetchCallName,\n\t\t\t\t\t\treason: progress.cancel.reason,\n\t\t\t\t\t},\n\t\t\t\t\terr,\n\t\t\t\t);\n\t\t\t\tthrow new NonRetryableError(\n\t\t\t\t\t\"runWithRetry was Aborted\",\n\t\t\t\t\tDriverErrorTypes.genericError,\n\t\t\t\t\t{\n\t\t\t\t\t\tdriverVersion: pkgVersion,\n\t\t\t\t\t\tfetchCallName,\n\t\t\t\t\t\treason: progress.cancel.reason,\n\t\t\t\t\t},\n\t\t\t\t);\n\t\t\t}\n\n\t\t\t// logging the first failed retry instead of every attempt. We want to avoid filling telemetry\n\t\t\t// when we have tight loop of retrying in offline mode, but we also want to know what caused\n\t\t\t// the failure in the first place\n\t\t\tif (numRetries === 0) {\n\t\t\t\tlogger.sendTelemetryEvent(\n\t\t\t\t\t{\n\t\t\t\t\t\teventName: `${fetchCallName}_firstFailed`,\n\t\t\t\t\t\tduration: performance.now() - startTime,\n\t\t\t\t\t\tfetchCallName,\n\t\t\t\t\t},\n\t\t\t\t\terr,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tnumRetries++;\n\t\t\tlastError = err;\n\t\t\t// If the error is throttling error, then wait for the specified time before retrying.\n\t\t\tretryAfterMs =\n\t\t\t\tgetRetryDelayFromError(err) ??\n\t\t\t\tMath.min(retryAfterMs * 2, calculateMaxWaitTime(err));\n\t\t\tif (progress.onRetry) {\n\t\t\t\tprogress.onRetry(retryAfterMs, err);\n\t\t\t}\n\t\t\tawait delay(retryAfterMs);\n\t\t}\n\t} while (!success);\n\tif (numRetries > 0) {\n\t\tlogger.sendTelemetryEvent(\n\t\t\t{\n\t\t\t\teventName: `${fetchCallName}_lastError`,\n\t\t\t\tretry: numRetries,\n\t\t\t\tduration: performance.now() - startTime,\n\t\t\t\tfetchCallName,\n\t\t\t},\n\t\t\tlastError,\n\t\t);\n\t}\n\t// eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n\treturn result!;\n}\n\nconst MaxReconnectDelayInMsWhenEndpointIsReachable = 30000;\nconst MaxReconnectDelayInMsWhenEndpointIsNotReachable = 8000;\n\n/**\n * In case endpoint(service or socket) is not reachable, then we maybe offline or may have got some transient error\n * not related to endpoint, in that case we want to try at faster pace and hence the max wait is lesser 8s as compared\n * to when endpoint is reachable in which case it is 30s.\n * @param error - error based on which we decide max wait time.\n * @returns Max wait time.\n * @public\n */\nexport function calculateMaxWaitTime(error: unknown): number {\n\treturn isFluidError(error) && error.getTelemetryProperties().endpointReached === true\n\t\t? MaxReconnectDelayInMsWhenEndpointIsReachable\n\t\t: MaxReconnectDelayInMsWhenEndpointIsNotReachable;\n}\n"]}
1
+ {"version":3,"file":"runWithRetry.js","sourceRoot":"","sources":["../src/runWithRetry.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { ITelemetryLoggerExt, isFluidError } from \"@fluidframework/telemetry-utils\";\nimport { performance } from \"@fluid-internal/client-utils\";\nimport { delay } from \"@fluidframework/core-utils\";\nimport { DriverErrorTypes } from \"@fluidframework/driver-definitions\";\nimport { canRetryOnError, getRetryDelayFromError } from \"./network\";\nimport { pkgVersion } from \"./packageVersion\";\nimport { NonRetryableError } from \".\";\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 * @public\n */\nexport interface IProgress {\n\t/**\n\t * Abort signal used to cancel operation.\n\t *\n\t * @remarks Note that most of the layers do not use this signal yet. We need to change that over time.\n\t * Please consult with API documentation / implementation.\n\t * Note that number of layers may not check this signal while holding this request in a queue,\n\t * so it may take a while it takes effect. This can be improved in the future.\n\t *\n\t * The layers in question are:\n\t *\n\t * - driver (RateLimiter)\n\t *\n\t * - runWithRetry\n\t */\n\tcancel?: AbortSignal;\n\n\t/**\n\t * Called whenever api returns cancellable error and the call is going to be retried.\n\t * Any exception thrown from this call back result in cancellation of operation\n\t * and propagation of thrown exception.\n\t * @param delayInMs - delay before next retry. This value will depend on internal back-off logic,\n\t * as well as information provided by service (like 429 error asking to wait for some time before retry)\n\t * @param error - error object returned from the call.\n\t */\n\tonRetry?(delayInMs: number, error: any): void;\n}\n\n/**\n * @public\n */\nexport async function runWithRetry<T>(\n\tapi: (cancel?: AbortSignal) => Promise<T>,\n\tfetchCallName: string,\n\tlogger: ITelemetryLoggerExt,\n\tprogress: IProgress,\n): Promise<T> {\n\tlet result: T | undefined;\n\tlet success = false;\n\t// We double this value in first try in when we calculate time to wait for in \"calculateMaxWaitTime\" function.\n\tlet retryAfterMs = 500; // has to be positive!\n\tlet numRetries = 0;\n\tconst startTime = performance.now();\n\tlet lastError: any;\n\tdo {\n\t\ttry {\n\t\t\tresult = await api(progress.cancel);\n\t\t\tsuccess = true;\n\t\t} catch (err) {\n\t\t\t// If it is not retriable, then just throw the error.\n\t\t\tif (!canRetryOnError(err)) {\n\t\t\t\tlogger.sendTelemetryEvent(\n\t\t\t\t\t{\n\t\t\t\t\t\teventName: `${fetchCallName}_cancel`,\n\t\t\t\t\t\tretry: numRetries,\n\t\t\t\t\t\tduration: performance.now() - startTime,\n\t\t\t\t\t\tfetchCallName,\n\t\t\t\t\t},\n\t\t\t\t\terr,\n\t\t\t\t);\n\t\t\t\tthrow err;\n\t\t\t}\n\n\t\t\tif (progress.cancel?.aborted === true) {\n\t\t\t\tlogger.sendTelemetryEvent(\n\t\t\t\t\t{\n\t\t\t\t\t\teventName: `${fetchCallName}_runWithRetryAborted`,\n\t\t\t\t\t\tretry: numRetries,\n\t\t\t\t\t\tduration: performance.now() - startTime,\n\t\t\t\t\t\tfetchCallName,\n\t\t\t\t\t\treason: progress.cancel.reason,\n\t\t\t\t\t},\n\t\t\t\t\terr,\n\t\t\t\t);\n\t\t\t\tthrow new NonRetryableError(\n\t\t\t\t\t\"runWithRetry was Aborted\",\n\t\t\t\t\tDriverErrorTypes.genericError,\n\t\t\t\t\t{\n\t\t\t\t\t\tdriverVersion: pkgVersion,\n\t\t\t\t\t\tfetchCallName,\n\t\t\t\t\t\treason: progress.cancel.reason,\n\t\t\t\t\t},\n\t\t\t\t);\n\t\t\t}\n\n\t\t\t// logging the first failed retry instead of every attempt. We want to avoid filling telemetry\n\t\t\t// when we have tight loop of retrying in offline mode, but we also want to know what caused\n\t\t\t// the failure in the first place\n\t\t\tif (numRetries === 0) {\n\t\t\t\tlogger.sendTelemetryEvent(\n\t\t\t\t\t{\n\t\t\t\t\t\teventName: `${fetchCallName}_firstFailed`,\n\t\t\t\t\t\tduration: performance.now() - startTime,\n\t\t\t\t\t\tfetchCallName,\n\t\t\t\t\t},\n\t\t\t\t\terr,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tnumRetries++;\n\t\t\tlastError = err;\n\t\t\t// Wait for the calculated time before retrying.\n\t\t\tretryAfterMs = calculateMaxWaitTime(retryAfterMs, err);\n\t\t\tif (progress.onRetry) {\n\t\t\t\tprogress.onRetry(retryAfterMs, err);\n\t\t\t}\n\t\t\tawait delay(retryAfterMs);\n\t\t}\n\t} while (!success);\n\tif (numRetries > 0) {\n\t\tlogger.sendTelemetryEvent(\n\t\t\t{\n\t\t\t\teventName: `${fetchCallName}_lastError`,\n\t\t\t\tretry: numRetries,\n\t\t\t\tduration: performance.now() - startTime,\n\t\t\t\tfetchCallName,\n\t\t\t},\n\t\t\tlastError,\n\t\t);\n\t}\n\t// eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n\treturn result!;\n}\n\nconst MaxReconnectDelayInMsWhenEndpointIsReachable = 60000;\nconst MaxReconnectDelayInMsWhenEndpointIsNotReachable = 8000;\n\n/**\n * Calculates time to wait for after an error based on the error and wait time for previous iteration.\n * In case endpoint(service or socket) is not reachable, then we maybe offline or may have got some\n * transient error not related to endpoint, in that case we want to try at faster pace and hence the\n * max wait is lesser 8s as compared to when endpoint is reachable in which case it is 60s.\n * @param delayMs - wait time for previous iteration\n * @param error - error based on which we decide wait time.\n * @returns Wait time to wait for.\n * @public\n */\nexport function calculateMaxWaitTime(delayMs: number, error: unknown): number {\n\tconst retryDelayFromError = getRetryDelayFromError(error);\n\tlet newDelayMs = Math.max(retryDelayFromError ?? 0, delayMs * 2);\n\tnewDelayMs = Math.min(\n\t\tdelayMs,\n\t\tisFluidError(error) && error.getTelemetryProperties().endpointReached === true\n\t\t\t? MaxReconnectDelayInMsWhenEndpointIsReachable\n\t\t\t: MaxReconnectDelayInMsWhenEndpointIsNotReachable,\n\t);\n\treturn newDelayMs;\n}\n"]}
@@ -5,7 +5,7 @@
5
5
  "toolPackages": [
6
6
  {
7
7
  "packageName": "@microsoft/api-extractor",
8
- "packageVersion": "7.38.0"
8
+ "packageVersion": "7.38.3"
9
9
  }
10
10
  ]
11
11
  }
@@ -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 = "2.0.0-internal.7.2.1";
8
+ export declare const pkgVersion = "2.0.0-internal.7.3.0";
9
9
  //# sourceMappingURL=packageVersion.d.ts.map
@@ -5,5 +5,5 @@
5
5
  * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY
6
6
  */
7
7
  export const pkgName = "@fluidframework/driver-utils";
8
- export const pkgVersion = "2.0.0-internal.7.2.1";
8
+ export const pkgVersion = "2.0.0-internal.7.3.0";
9
9
  //# sourceMappingURL=packageVersion.js.map
@@ -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,sBAAsB,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 = \"2.0.0-internal.7.2.1\";\n"]}
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,sBAAsB,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 = \"2.0.0-internal.7.3.0\";\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"parallelRequests.d.ts","sourceRoot":"","sources":["../src/parallelRequests.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,oBAAoB,EAAE,MAAM,iCAAiC,CAAC;AAEvE,OAAO,EAAE,mBAAmB,EAAoB,MAAM,iCAAiC,CAAC;AACxF,OAAO,EAAE,yBAAyB,EAAE,MAAM,sCAAsC,CAAC;AACjF,OAAO,EAAE,kBAAkB,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,oCAAoC,CAAC;AAWhG;;;;;;;;;;;;GAYG;AACH,qBAAa,gBAAgB,CAAC,CAAC;IAmB7B,OAAO,CAAC,EAAE;IACV,OAAO,CAAC,QAAQ,CAAC,WAAW;IAC5B,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,eAAe;IAOhC,OAAO,CAAC,QAAQ,CAAC,gBAAgB;IA5BlC,OAAO,CAAC,eAAe,CAAS;IAChC,OAAO,CAAC,aAAa,CAAS;IAC9B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA0B;IAClD,OAAO,CAAC,YAAY,CAA2B;IAC/C,OAAO,CAAC,gBAAgB,CAAK;IAC7B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAwB;IACjD,OAAO,CAAC,QAAQ,CAAK;IACrB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAU;IAEjC,OAAO,KAAK,OAAO,GAElB;IACD,IAAW,QAAQ,YAElB;gBAGA,IAAI,EAAE,MAAM,EACJ,EAAE,EAAE,MAAM,GAAG,SAAS,EACb,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,mBAAmB,EAC3B,eAAe,EAAE,CACjC,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EACZ,EAAE,EAAE,MAAM,EACV,QAAQ,EAAE,OAAO,EACjB,KAAK,EAAE,oBAAoB,KACvB,OAAO,CAAC;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,MAAM,EAAE,OAAO,CAAC;QAAC,OAAO,EAAE,CAAC,EAAE,CAAA;KAAE,CAAC,EAChD,gBAAgB,EAAE,CAAC,OAAO,EAAE,CAAC,EAAE,KAAK,IAAI;IAOnD,MAAM;IAOA,GAAG,CAAC,WAAW,EAAE,MAAM;IAapC,OAAO,CAAC,IAAI;IAaZ,OAAO,CAAC,IAAI;IAOZ,OAAO,CAAC,QAAQ;IAqChB,OAAO,CAAC,YAAY;IAyBpB,OAAO,CAAC,UAAU;YAQJ,cAAc;CA6J5B;AAED;;;;GAIG;AACH,qBAAa,KAAK,CAAC,CAAC,CAAE,YAAW,OAAO,CAAC,CAAC,CAAC;IAC1C,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAmC;IACzD,OAAO,CAAC,QAAQ,CAAyC;IACzD,OAAO,CAAC,IAAI,CAAS;IAEd,SAAS,CAAC,KAAK,EAAE,CAAC;IAIlB,SAAS,CAAC,KAAK,EAAE,GAAG;IAKpB,QAAQ;IAKf,SAAS,CAAC,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC;IAWtC,IAAI,IAAI,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC;CAU9C;AA6ID;;;;;;;;;;;;GAYG;AACH,wBAAgB,UAAU,CACzB,GAAG,EAAE,CACJ,IAAI,EAAE,MAAM,EACZ,EAAE,EAAE,MAAM,EACV,cAAc,EAAE,oBAAoB,KAChC,OAAO,CAAC,kBAAkB,CAAC,EAChC,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,GAAG,SAAS,EAC3B,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,mBAAmB,EAC3B,MAAM,CAAC,EAAE,WAAW,EACpB,YAAY,CAAC,EAAE,MAAM,GACnB,OAAO,CAAC,yBAAyB,EAAE,CAAC,CAwGtC;AAED;;GAEG;AACH,eAAO,MAAM,kBAAkB,EAAE,OAAO,CAAC,yBAAyB,EAAE,CAInE,CAAC;AAEF;;GAEG;AACH,wBAAgB,kBAAkB,CACjC,WAAW,EAAE,OAAO,CAAC,yBAAyB,EAAE,CAAC,GAC/C,OAAO,CAAC,yBAAyB,EAAE,CAAC,CAYtC;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,CAAC,EAC/B,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,EAClB,OAAO,EAAE,CAAC,KAAK,EAAE,aAAa,CAAC,CAAC,CAAC,KAAK,IAAI,GACxC,OAAO,CAAC,CAAC,CAAC,CAQZ"}
1
+ {"version":3,"file":"parallelRequests.d.ts","sourceRoot":"","sources":["../src/parallelRequests.ts"],"names":[],"mappings":"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"}
@@ -9,8 +9,9 @@ import { getRetryDelayFromError, canRetryOnError, createGenericNetworkError } fr
9
9
  import { logNetworkFailure } from "./networkUtils";
10
10
  // For now, this package is versioned and released in unison with the specific drivers
11
11
  import { pkgVersion as driverVersion } from "./packageVersion";
12
- const MaxFetchDelayInMs = 10000;
13
- const MissingFetchDelayInMs = 100;
12
+ import { calculateMaxWaitTime } from "./runWithRetry";
13
+ // We double this value in first try in when we calculate time to wait for in "calculateMaxWaitTime" function.
14
+ const MissingFetchDelayInMs = 50;
14
15
  /**
15
16
  * Helper class to organize parallel fetching of data
16
17
  * It can be used to concurrently do many requests, while consuming
@@ -334,9 +335,10 @@ async function getSingleOpBatch(get, props, strongTo, logger, signal, scenarioNa
334
335
  let retry = 0;
335
336
  const nothing = { partial: false, cancel: true, payload: [] };
336
337
  let waitStartTime = 0;
338
+ let waitTime = MissingFetchDelayInMs;
337
339
  while (signal?.aborted !== true) {
338
340
  retry++;
339
- let delay = Math.min(MaxFetchDelayInMs, MissingFetchDelayInMs * Math.pow(2, retry));
341
+ let lastError;
340
342
  const startTime = performance.now();
341
343
  try {
342
344
  // Issue async request for deltas
@@ -373,6 +375,7 @@ async function getSingleOpBatch(get, props, strongTo, logger, signal, scenarioNa
373
375
  }
374
376
  }
375
377
  catch (error) {
378
+ lastError = error;
376
379
  const canRetry = canRetryOnError(error);
377
380
  const retryAfter = getRetryDelayFromError(error);
378
381
  // This will log to error table only if the error is non-retryable
@@ -388,10 +391,6 @@ async function getSingleOpBatch(get, props, strongTo, logger, signal, scenarioNa
388
391
  // It's game over scenario.
389
392
  throw error;
390
393
  }
391
- if (retryAfter !== undefined) {
392
- // If the error told us to wait, then we will wait for that specific amount rather than the default.
393
- delay = retryAfter;
394
- }
395
394
  }
396
395
  if (telemetryEvent === undefined) {
397
396
  waitStartTime = performance.now();
@@ -399,10 +398,11 @@ async function getSingleOpBatch(get, props, strongTo, logger, signal, scenarioNa
399
398
  eventName: "GetDeltasWaitTime",
400
399
  });
401
400
  }
401
+ waitTime = calculateMaxWaitTime(waitTime, lastError);
402
402
  // If we get here something has gone wrong - either got an unexpected empty set of messages back or a real error.
403
403
  // Either way we will wait a little bit before retrying.
404
404
  await new Promise((resolve) => {
405
- setTimeout(resolve, delay);
405
+ setTimeout(resolve, waitTime);
406
406
  });
407
407
  // If we believe we're offline, we assume there's no point in trying until we at least think we're online.
408
408
  // NOTE: This isn't strictly true for drivers that don't require network (e.g. local driver). Really this logic
@@ -1 +1 @@
1
- {"version":3,"file":"parallelRequests.js","sourceRoot":"","sources":["../src/parallelRequests.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\nimport { performance } from \"@fluid-internal/client-utils\";\nimport { ITelemetryProperties } from \"@fluidframework/core-interfaces\";\nimport { assert, Deferred } from \"@fluidframework/core-utils\";\nimport { ITelemetryLoggerExt, PerformanceEvent } from \"@fluidframework/telemetry-utils\";\nimport { ISequencedDocumentMessage } from \"@fluidframework/protocol-definitions\";\nimport { IDeltasFetchResult, IStream, IStreamResult } from \"@fluidframework/driver-definitions\";\nimport { getRetryDelayFromError, canRetryOnError, createGenericNetworkError } from \"./network\";\nimport { logNetworkFailure } from \"./networkUtils\";\n// For now, this package is versioned and released in unison with the specific drivers\nimport { pkgVersion as driverVersion } from \"./packageVersion\";\n\nconst MaxFetchDelayInMs = 10000;\nconst MissingFetchDelayInMs = 100;\n\ntype WorkingState = \"working\" | \"done\" | \"canceled\";\n\n/**\n * Helper class to organize parallel fetching of data\n * It can be used to concurrently do many requests, while consuming\n * data in the right order. Take a look at UT for examples.\n * @param concurrency - level of concurrency\n * @param from - starting point of fetching data (inclusive)\n * @param to - ending point of fetching data. exclusive, or undefined if unknown\n * @param payloadSize - batch size\n * @param logger - logger to use\n * @param requestCallback - callback to request batches\n * @returns Queue that can be used to retrieve data\n * @public\n */\nexport class ParallelRequests<T> {\n\tprivate latestRequested: number;\n\tprivate nextToDeliver: number;\n\tprivate readonly results = new Map<number, T[]>();\n\tprivate workingState: WorkingState = \"working\";\n\tprivate requestsInFlight = 0;\n\tprivate readonly endEvent = new Deferred<void>();\n\tprivate requests = 0;\n\tprivate readonly knewTo: boolean;\n\n\tprivate get working() {\n\t\treturn this.workingState === \"working\";\n\t}\n\tpublic get canceled() {\n\t\treturn this.workingState === \"canceled\";\n\t}\n\n\tconstructor(\n\t\tfrom: number,\n\t\tprivate to: number | undefined,\n\t\tprivate readonly payloadSize: number,\n\t\tprivate readonly logger: ITelemetryLoggerExt,\n\t\tprivate readonly requestCallback: (\n\t\t\trequest: number,\n\t\t\tfrom: number,\n\t\t\tto: number,\n\t\t\tstrongTo: boolean,\n\t\t\tprops: ITelemetryProperties,\n\t\t) => Promise<{ partial: boolean; cancel: boolean; payload: T[] }>,\n\t\tprivate readonly responseCallback: (payload: T[]) => void,\n\t) {\n\t\tthis.latestRequested = from;\n\t\tthis.nextToDeliver = from;\n\t\tthis.knewTo = to !== undefined;\n\t}\n\n\tpublic cancel() {\n\t\tif (this.working) {\n\t\t\tthis.workingState = \"canceled\";\n\t\t\tthis.endEvent.resolve();\n\t\t}\n\t}\n\n\tpublic async run(concurrency: number) {\n\t\tassert(concurrency > 0, 0x102 /* \"invalid level of concurrency\" */);\n\t\tassert(this.working, 0x103 /* \"trying to parallel run while not working\" */);\n\n\t\tlet c = concurrency;\n\t\twhile (c > 0) {\n\t\t\tc--;\n\t\t\tthis.addRequest();\n\t\t}\n\t\tthis.dispatch(); // will recalculate and trigger this.endEvent if needed\n\t\treturn this.endEvent.promise;\n\t}\n\n\tprivate done() {\n\t\t// We should satisfy request fully.\n\t\tassert(this.to !== undefined, 0x104 /* \"undefined end point for parallel fetch\" */);\n\t\tassert(\n\t\t\tthis.nextToDeliver >= this.to,\n\t\t\t0x105 /* \"unexpected end point for parallel fetch\" */,\n\t\t);\n\t\tif (this.working) {\n\t\t\tthis.workingState = \"done\";\n\t\t\tthis.endEvent.resolve();\n\t\t}\n\t}\n\n\tprivate fail(error) {\n\t\tif (this.working) {\n\t\t\tthis.workingState = \"done\";\n\t\t\tthis.endEvent.reject(error);\n\t\t}\n\t}\n\n\tprivate dispatch() {\n\t\twhile (this.working) {\n\t\t\tconst value = this.results.get(this.nextToDeliver);\n\t\t\tif (value === undefined) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tthis.results.delete(this.nextToDeliver);\n\t\t\tassert(\n\t\t\t\tvalue.length <= this.payloadSize,\n\t\t\t\t0x1d9 /* \"addRequestCore() should break into smaller chunks\" */,\n\t\t\t);\n\t\t\tthis.nextToDeliver += value.length;\n\t\t\tthis.responseCallback(value);\n\t\t}\n\n\t\t// Account for cancellation - state might be not in consistent state on cancelling operation\n\t\tif (this.working) {\n\t\t\tif (this.requestsInFlight === 0) {\n\t\t\t\t// we should have dispatched everything, no matter whether we knew about the end or not.\n\t\t\t\t// see comment in addRequestCore() around throwing away chunk if it's above this.to\n\t\t\t\tassert(\n\t\t\t\t\tthis.results.size === 0,\n\t\t\t\t\t0x107 /* \"ending dispatch with remaining results to be sent\" */,\n\t\t\t\t);\n\t\t\t\tthis.done();\n\t\t\t} else if (this.to !== undefined && this.nextToDeliver >= this.to) {\n\t\t\t\t// Learned about the end and dispatched all the ops up to it.\n\t\t\t\t// Ignore all the in-flight requests above boundary - unblock caller sooner.\n\t\t\t\tassert(\n\t\t\t\t\t!this.knewTo,\n\t\t\t\t\t0x108 /* \"ending results dispatch but knew in advance about more requests\" */,\n\t\t\t\t);\n\t\t\t\tthis.done();\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate getNextChunk() {\n\t\tif (!this.working) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tconst from = this.latestRequested;\n\t\tif (this.to !== undefined) {\n\t\t\tif (this.to <= from) {\n\t\t\t\treturn undefined;\n\t\t\t}\n\t\t}\n\n\t\t// this.latestRequested\n\t\t// inclusive on the right side! Exclusive on the left.\n\t\tthis.latestRequested += this.payloadSize;\n\n\t\tif (this.to !== undefined) {\n\t\t\tthis.latestRequested = Math.min(this.to, this.latestRequested);\n\t\t}\n\n\t\tassert(from < this.latestRequested, 0x109 /* \"unexpected next chunk position\" */);\n\n\t\treturn { from, to: this.latestRequested };\n\t}\n\n\tprivate addRequest() {\n\t\tconst chunk = this.getNextChunk();\n\t\tif (chunk === undefined) {\n\t\t\treturn;\n\t\t}\n\t\tthis.addRequestCore(chunk.from, chunk.to).catch(this.fail.bind(this));\n\t}\n\n\tprivate async addRequestCore(fromArg: number, toArg: number) {\n\t\tassert(this.working, 0x10a /* \"cannot add parallel request while not working\" */);\n\n\t\tlet from = fromArg;\n\t\tlet to = toArg;\n\n\t\t// to & from are exclusive\n\t\tthis.requestsInFlight++;\n\t\twhile (this.working) {\n\t\t\tconst requestedLength = to - from;\n\t\t\tassert(requestedLength > 0, 0x10b /* \"invalid parallel request range\" */);\n\n\t\t\t// We should not be wasting time asking for something useless.\n\t\t\tif (this.to !== undefined) {\n\t\t\t\tassert(from < this.to, 0x10c /* \"invalid parallel request start point\" */);\n\t\t\t\tassert(to <= this.to, 0x10d /* \"invalid parallel request end point\" */);\n\t\t\t}\n\n\t\t\tthis.requests++;\n\n\t\t\tconst promise = this.requestCallback(\n\t\t\t\tthis.requests,\n\t\t\t\tfrom,\n\t\t\t\tto,\n\t\t\t\tthis.to !== undefined,\n\t\t\t\t{},\n\t\t\t);\n\n\t\t\t// dispatch any prior received data\n\t\t\tthis.dispatch();\n\n\t\t\tconst { payload, cancel, partial } = await promise;\n\n\t\t\tif (cancel) {\n\t\t\t\tthis.cancel();\n\t\t\t}\n\n\t\t\tif (this.to !== undefined && from >= this.to) {\n\t\t\t\t// while we were waiting for response, we learned on what is the boundary\n\t\t\t\t// We can get here (with actual result!) if situation changed while this request was in\n\t\t\t\t// flight, i.e. the end was extended over what we learn in some other request\n\t\t\t\t// While it's useful not to throw this result, this is very corner cases and makes logic\n\t\t\t\t// (including consistency checks) much harder to write correctly.\n\t\t\t\t// So for now, we are throwing this result out the window.\n\t\t\t\tassert(\n\t\t\t\t\t!this.knewTo,\n\t\t\t\t\t0x10e /* \"should not throw result if we knew about boundary in advance\" */,\n\t\t\t\t);\n\t\t\t\t// Learn how often it happens and if it's too wasteful to throw these chunks.\n\t\t\t\t// If it pops into our view a lot, we would need to reconsider how we approach it.\n\t\t\t\t// Note that this is not visible to user other than potentially not hitting 100% of\n\t\t\t\t// what we can in perf domain.\n\t\t\t\tif (payload.length !== 0) {\n\t\t\t\t\tthis.logger.sendErrorEvent({\n\t\t\t\t\t\teventName: \"ParallelRequests_GotExtra\",\n\t\t\t\t\t\tfrom,\n\t\t\t\t\t\tto,\n\t\t\t\t\t\tend: this.to,\n\t\t\t\t\t\tlength: payload.length,\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tif (this.working) {\n\t\t\t\tconst fromOrig = from;\n\t\t\t\tconst length = payload.length;\n\t\t\t\tlet fullChunk = requestedLength <= length; // we can possible get more than we asked.\n\n\t\t\t\tif (length !== 0) {\n\t\t\t\t\t// We can get more than we asked for!\n\t\t\t\t\t// This can screw up logic in dispatch!\n\t\t\t\t\t// So push only batch size, and keep the rest for later - if conditions are favorable, we\n\t\t\t\t\t// will be able to use it. If not (parallel request overlapping these ops), it's easier to\n\t\t\t\t\t// discard them and wait for another (overlapping) request to come in later.\n\t\t\t\t\tif (requestedLength < length) {\n\t\t\t\t\t\t// This is error in a sense that it's not expected and likely points bug in other layer.\n\t\t\t\t\t\t// This layer copes with this situation just fine.\n\t\t\t\t\t\tthis.logger.sendTelemetryEvent({\n\t\t\t\t\t\t\teventName: \"ParallelRequests_Over\",\n\t\t\t\t\t\t\tfrom,\n\t\t\t\t\t\t\tto,\n\t\t\t\t\t\t\tlength,\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t\tconst data = payload.splice(0, requestedLength);\n\t\t\t\t\tthis.results.set(from, data);\n\t\t\t\t\tfrom += data.length;\n\t\t\t\t} else {\n\t\t\t\t\t// 1. empty (partial) chunks should not be returned by various caching / adapter layers -\n\t\t\t\t\t// they should fall back to next layer. This might be important invariant to hold to ensure\n\t\t\t\t\t// that we are less likely have bugs where such layer would keep returning empty partial\n\t\t\t\t\t// result on each call.\n\t\t\t\t\t// 2. Current invariant is that callback does retries until it gets something,\n\t\t\t\t\t// with the goal of failing if zero data is retrieved in given amount of time.\n\t\t\t\t\t// This is very specific property of storage / ops, so this logic is not here, but given only\n\t\t\t\t\t// one user of this class, we assert that to catch issues earlier.\n\t\t\t\t\t// These invariant can be relaxed if needed.\n\t\t\t\t\tassert(\n\t\t\t\t\t\t!partial,\n\t\t\t\t\t\t0x10f /* \"empty/partial chunks should not be returned by caching\" */,\n\t\t\t\t\t);\n\t\t\t\t\tassert(\n\t\t\t\t\t\t!this.knewTo,\n\t\t\t\t\t\t0x110 /* \"callback should retry until valid fetch before it learns new boundary\" */,\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\tif (!partial && !fullChunk) {\n\t\t\t\t\tif (!this.knewTo) {\n\t\t\t\t\t\tif (this.to === undefined || this.to > from) {\n\t\t\t\t\t\t\t// The END\n\t\t\t\t\t\t\tthis.to = from;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\t// We know that there are more items to be retrieved\n\t\t\t\t\t// Can we get partial chunk? Ideally storage indicates that's not a full chunk\n\t\t\t\t\t// Note that it's possible that not all ops hit storage yet.\n\t\t\t\t\t// We will come back to request more, and if we can't get any more ops soon, it's\n\t\t\t\t\t// catastrophic failure (see comment above on responsibility of callback to return something)\n\t\t\t\t\t// This layer will just keep trying until it gets full set.\n\t\t\t\t\tthis.logger.sendPerformanceEvent({\n\t\t\t\t\t\teventName: \"ParallelRequests_Partial\",\n\t\t\t\t\t\tfrom: fromOrig,\n\t\t\t\t\t\tto,\n\t\t\t\t\t\tlength,\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\tif (to === this.latestRequested) {\n\t\t\t\t\t// we can go after full chunk at the end if we received partial chunk, or more than asked\n\t\t\t\t\t// Also if we got more than we asked to, we can actually use those ops!\n\t\t\t\t\twhile (payload.length !== 0) {\n\t\t\t\t\t\tconst data = payload.splice(0, requestedLength);\n\t\t\t\t\t\tthis.results.set(from, data);\n\t\t\t\t\t\tfrom += data.length;\n\t\t\t\t\t}\n\n\t\t\t\t\tthis.latestRequested = from;\n\t\t\t\t\tfullChunk = true;\n\t\t\t\t}\n\n\t\t\t\tif (fullChunk) {\n\t\t\t\t\tconst chunk = this.getNextChunk();\n\t\t\t\t\tif (chunk === undefined) {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tfrom = chunk.from;\n\t\t\t\t\tto = chunk.to;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tthis.requestsInFlight--;\n\t\tthis.dispatch();\n\t}\n}\n\n/**\n * Helper queue class to allow async push / pull\n * It's essentially a pipe allowing multiple writers, and single reader\n * @public\n */\nexport class Queue<T> implements IStream<T> {\n\tprivate readonly queue: Promise<IStreamResult<T>>[] = [];\n\tprivate deferred: Deferred<IStreamResult<T>> | undefined;\n\tprivate done = false;\n\n\tpublic pushValue(value: T) {\n\t\tthis.pushCore(Promise.resolve({ done: false, value }));\n\t}\n\n\tpublic pushError(error: any) {\n\t\tthis.pushCore(Promise.reject(error));\n\t\tthis.done = true;\n\t}\n\n\tpublic pushDone() {\n\t\tthis.pushCore(Promise.resolve({ done: true }));\n\t\tthis.done = true;\n\t}\n\n\tprotected pushCore(value: Promise<IStreamResult<T>>) {\n\t\tassert(!this.done, 0x112 /* \"cannot push onto queue if done\" */);\n\t\tif (this.deferred) {\n\t\t\tassert(this.queue.length === 0, 0x113 /* \"deferred queue should be empty\" */);\n\t\t\tthis.deferred.resolve(value);\n\t\t\tthis.deferred = undefined;\n\t\t} else {\n\t\t\tthis.queue.push(value);\n\t\t}\n\t}\n\n\tpublic async read(): Promise<IStreamResult<T>> {\n\t\tassert(this.deferred === undefined, 0x114 /* \"cannot pop if deferred\" */);\n\t\tconst value = this.queue.shift();\n\t\tif (value !== undefined) {\n\t\t\treturn value;\n\t\t}\n\t\tassert(!this.done, 0x115 /* \"queue should not be done during pop\" */);\n\t\tthis.deferred = new Deferred<IStreamResult<T>>();\n\t\treturn this.deferred.promise;\n\t}\n}\n\nconst waitForOnline = async (): Promise<void> => {\n\t// Only wait if we have a strong signal that we're offline - otherwise assume we're online.\n\tif (globalThis.navigator?.onLine === false && globalThis.addEventListener !== undefined) {\n\t\treturn new Promise<void>((resolve) => {\n\t\t\tconst resolveAndRemoveListener = () => {\n\t\t\t\tresolve();\n\t\t\t\tglobalThis.removeEventListener(\"online\", resolveAndRemoveListener);\n\t\t\t};\n\t\t\tglobalThis.addEventListener(\"online\", resolveAndRemoveListener);\n\t\t});\n\t}\n};\n\n/**\n * Retrieve single batch of ops\n * @param request - request index\n * @param from - inclusive boundary\n * @param to - exclusive boundary\n * @param telemetryEvent - telemetry event used to track consecutive batch of requests\n * @param strongTo - tells if ops in range from...to have to be there and have to be retrieved.\n * If false, returning less ops would mean we reached end of file.\n * @param logger - logger object to use to log progress & errors\n * @param signal - cancelation signal\n * @param scenarioName - reason for fetching ops\n * @returns An object with resulting ops and cancellation / partial result flags\n */\nasync function getSingleOpBatch(\n\tget: (telemetryProps: ITelemetryProperties) => Promise<IDeltasFetchResult>,\n\tprops: ITelemetryProperties,\n\tstrongTo: boolean,\n\tlogger: ITelemetryLoggerExt,\n\tsignal?: AbortSignal,\n\tscenarioName?: string,\n): Promise<{ partial: boolean; cancel: boolean; payload: ISequencedDocumentMessage[] }> {\n\tlet lastSuccessTime: number | undefined;\n\tlet totalRetryAfterTime = 0;\n\tlet telemetryEvent: PerformanceEvent | undefined;\n\tlet retry: number = 0;\n\tconst nothing = { partial: false, cancel: true, payload: [] };\n\tlet waitStartTime: number = 0;\n\n\twhile (signal?.aborted !== true) {\n\t\tretry++;\n\t\tlet delay = Math.min(MaxFetchDelayInMs, MissingFetchDelayInMs * Math.pow(2, retry));\n\t\tconst startTime = performance.now();\n\n\t\ttry {\n\t\t\t// Issue async request for deltas\n\t\t\tconst { messages, partialResult } = await get(\n\t\t\t\t{ ...props, retry } /* telemetry props */,\n\t\t\t);\n\n\t\t\t// If we got messages back, return them. Return regardless of whether we got messages back if we didn't\n\t\t\t// specify a \"to\", since we don't have an expectation of how many to receive.\n\t\t\tif (messages.length !== 0 || !strongTo) {\n\t\t\t\t// Report this event if we waited to fetch ops due to being offline or throttling.\n\t\t\t\ttelemetryEvent?.end({\n\t\t\t\t\tduration: totalRetryAfterTime,\n\t\t\t\t\t...props,\n\t\t\t\t\treason: scenarioName,\n\t\t\t\t});\n\t\t\t\treturn { payload: messages, cancel: false, partial: partialResult };\n\t\t\t}\n\n\t\t\t// Otherwise, the storage gave us back an empty set of ops but we were expecting a non-empty set.\n\n\t\t\tif (lastSuccessTime === undefined) {\n\t\t\t\t// Take timestamp of the first time server responded successfully, even though it wasn't with the ops we asked for.\n\t\t\t\t// If we keep getting empty responses we'll eventually fail out below.\n\t\t\t\tlastSuccessTime = performance.now();\n\t\t\t} else if (performance.now() - lastSuccessTime > 30000) {\n\t\t\t\t// If we are connected and receiving proper responses from server, but can't get any ops back,\n\t\t\t\t// then give up after some time. This likely indicates the issue with ordering service not flushing\n\t\t\t\t// ops to storage quick enough, and possibly waiting for summaries, while summarizer can't get\n\t\t\t\t// current as it can't get ops.\n\t\t\t\tthrow createGenericNetworkError(\n\t\t\t\t\t// pre-0.58 error message: failedToRetrieveOpsFromStorage:TooManyRetries\n\t\t\t\t\t\"Failed to retrieve ops from storage (Too Many Retries)\",\n\t\t\t\t\t{ canRetry: false },\n\t\t\t\t\t{\n\t\t\t\t\t\tretry,\n\t\t\t\t\t\tdriverVersion,\n\t\t\t\t\t\t...props,\n\t\t\t\t\t},\n\t\t\t\t);\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tconst canRetry = canRetryOnError(error);\n\n\t\t\tconst retryAfter = getRetryDelayFromError(error);\n\n\t\t\t// This will log to error table only if the error is non-retryable\n\t\t\tlogNetworkFailure(\n\t\t\t\tlogger,\n\t\t\t\t{\n\t\t\t\t\teventName: \"GetDeltas_Error\",\n\t\t\t\t\t...props,\n\t\t\t\t\tretry,\n\t\t\t\t\tduration: performance.now() - startTime,\n\t\t\t\t\tretryAfter,\n\t\t\t\t\treason: scenarioName,\n\t\t\t\t},\n\t\t\t\terror,\n\t\t\t);\n\n\t\t\tif (!canRetry) {\n\t\t\t\t// It's game over scenario.\n\t\t\t\tthrow error;\n\t\t\t}\n\n\t\t\tif (retryAfter !== undefined) {\n\t\t\t\t// If the error told us to wait, then we will wait for that specific amount rather than the default.\n\t\t\t\tdelay = retryAfter;\n\t\t\t}\n\t\t}\n\n\t\tif (telemetryEvent === undefined) {\n\t\t\twaitStartTime = performance.now();\n\t\t\ttelemetryEvent = PerformanceEvent.start(logger, {\n\t\t\t\teventName: \"GetDeltasWaitTime\",\n\t\t\t});\n\t\t}\n\n\t\t// If we get here something has gone wrong - either got an unexpected empty set of messages back or a real error.\n\t\t// Either way we will wait a little bit before retrying.\n\t\tawait new Promise<void>((resolve) => {\n\t\t\tsetTimeout(resolve, delay);\n\t\t});\n\n\t\t// If we believe we're offline, we assume there's no point in trying until we at least think we're online.\n\t\t// NOTE: This isn't strictly true for drivers that don't require network (e.g. local driver). Really this logic\n\t\t// should probably live in the driver.\n\t\tawait waitForOnline();\n\t\ttotalRetryAfterTime += performance.now() - waitStartTime;\n\t}\n\n\treturn nothing;\n}\n\n/**\n * Request ops from storage\n * @param get - Getter callback to get individual batches\n * @param concurrency - Number of concurrent requests to make\n * @param fromTotal - starting sequence number to fetch (inclusive)\n * @param toTotal - max (exclusive) sequence number to fetch\n * @param payloadSize - Payload size\n * @param logger - Logger to log progress and errors\n * @param signal - Cancelation signal\n * @param scenarioName - Reason for fetching ops\n * @returns Messages fetched\n * @public\n */\nexport function requestOps(\n\tget: (\n\t\tfrom: number,\n\t\tto: number,\n\t\ttelemetryProps: ITelemetryProperties,\n\t) => Promise<IDeltasFetchResult>,\n\tconcurrency: number,\n\tfromTotal: number,\n\ttoTotal: number | undefined,\n\tpayloadSize: number,\n\tlogger: ITelemetryLoggerExt,\n\tsignal?: AbortSignal,\n\tscenarioName?: string,\n): IStream<ISequencedDocumentMessage[]> {\n\tlet requests = 0;\n\tlet lastFetch: number | undefined;\n\tlet length = 0;\n\tconst queue = new Queue<ISequencedDocumentMessage[]>();\n\n\tconst propsTotal: ITelemetryProperties = {\n\t\tfromTotal,\n\t\ttoTotal,\n\t};\n\n\tconst telemetryEvent = PerformanceEvent.start(logger, {\n\t\teventName: \"GetDeltas\",\n\t\t...propsTotal,\n\t\treason: scenarioName,\n\t});\n\n\tconst manager = new ParallelRequests<ISequencedDocumentMessage>(\n\t\tfromTotal,\n\t\ttoTotal,\n\t\tpayloadSize,\n\t\tlogger,\n\t\tasync (\n\t\t\trequest: number,\n\t\t\tfrom: number,\n\t\t\tto: number,\n\t\t\tstrongTo: boolean,\n\t\t\tpropsPerRequest: ITelemetryProperties,\n\t\t) => {\n\t\t\trequests++;\n\t\t\treturn getSingleOpBatch(\n\t\t\t\tasync (propsAll) => get(from, to, propsAll),\n\t\t\t\t{ request, from, to, ...propsTotal, ...propsPerRequest },\n\t\t\t\tstrongTo,\n\t\t\t\tlogger,\n\t\t\t\tsignal,\n\t\t\t\tscenarioName,\n\t\t\t);\n\t\t},\n\t\t(deltas: ISequencedDocumentMessage[]) => {\n\t\t\t// Assert continuing and right start.\n\t\t\tif (lastFetch === undefined) {\n\t\t\t\tassert(deltas[0].sequenceNumber === fromTotal, 0x26d /* \"wrong start\" */);\n\t\t\t} else {\n\t\t\t\tassert(deltas[0].sequenceNumber === lastFetch + 1, 0x26e /* \"wrong start\" */);\n\t\t\t}\n\t\t\tlastFetch = deltas[deltas.length - 1].sequenceNumber;\n\t\t\tassert(\n\t\t\t\tlastFetch - deltas[0].sequenceNumber + 1 === deltas.length,\n\t\t\t\t0x26f /* \"continuous and no duplicates\" */,\n\t\t\t);\n\t\t\tlength += deltas.length;\n\t\t\tqueue.pushValue(deltas);\n\t\t},\n\t);\n\n\t// Implement faster cancellation. getSingleOpBatch() checks signal, but only in between\n\t// waits (up to 10 seconds) and fetches (can take infinite amount of time).\n\t// While every such case should be improved and take into account signal (and thus cancel immediately),\n\t// it is beneficial to have catch-all\n\tconst listener = (event: Event) => {\n\t\tmanager.cancel();\n\t};\n\tif (signal !== undefined) {\n\t\tsignal.addEventListener(\"abort\", listener);\n\t}\n\n\tmanager\n\t\t.run(concurrency)\n\t\t.finally(() => {\n\t\t\tif (signal !== undefined) {\n\t\t\t\tsignal.removeEventListener(\"abort\", listener);\n\t\t\t}\n\t\t})\n\t\t.then(() => {\n\t\t\tconst props = {\n\t\t\t\tlastFetch,\n\t\t\t\tlength,\n\t\t\t\trequests,\n\t\t\t};\n\t\t\tif (manager.canceled) {\n\t\t\t\ttelemetryEvent.cancel({ ...props, error: \"ops request cancelled by client\" });\n\t\t\t} else {\n\t\t\t\tassert(\n\t\t\t\t\ttoTotal === undefined || (lastFetch !== undefined && lastFetch >= toTotal - 1),\n\t\t\t\t\t0x270 /* \"All requested ops fetched\" */,\n\t\t\t\t);\n\t\t\t\ttelemetryEvent.end(props);\n\t\t\t}\n\t\t\tqueue.pushDone();\n\t\t})\n\t\t.catch((error) => {\n\t\t\ttelemetryEvent.cancel(\n\t\t\t\t{\n\t\t\t\t\tlastFetch,\n\t\t\t\t\tlength,\n\t\t\t\t\trequests,\n\t\t\t\t},\n\t\t\t\terror,\n\t\t\t);\n\t\t\tqueue.pushError(error);\n\t\t});\n\n\treturn queue;\n}\n\n/**\n * @public\n */\nexport const emptyMessageStream: IStream<ISequencedDocumentMessage[]> = {\n\tread: async () => {\n\t\treturn { done: true };\n\t},\n};\n\n/**\n * @public\n */\nexport function streamFromMessages(\n\tmessagesArg: Promise<ISequencedDocumentMessage[]>,\n): IStream<ISequencedDocumentMessage[]> {\n\tlet messages: Promise<ISequencedDocumentMessage[]> | undefined = messagesArg;\n\treturn {\n\t\tread: async () => {\n\t\t\tif (messages === undefined) {\n\t\t\t\treturn { done: true };\n\t\t\t}\n\t\t\tconst value = await messages;\n\t\t\tmessages = undefined;\n\t\t\treturn value.length === 0 ? { done: true } : { done: false, value };\n\t\t},\n\t};\n}\n\n/**\n * @public\n */\nexport function streamObserver<T>(\n\tstream: IStream<T>,\n\thandler: (value: IStreamResult<T>) => void,\n): IStream<T> {\n\treturn {\n\t\tread: async () => {\n\t\t\tconst value = await stream.read();\n\t\t\thandler(value);\n\t\t\treturn value;\n\t\t},\n\t};\n}\n"]}
1
+ {"version":3,"file":"parallelRequests.js","sourceRoot":"","sources":["../src/parallelRequests.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\nimport { performance } from \"@fluid-internal/client-utils\";\nimport { ITelemetryProperties } from \"@fluidframework/core-interfaces\";\nimport { assert, Deferred } from \"@fluidframework/core-utils\";\nimport { ITelemetryLoggerExt, PerformanceEvent } from \"@fluidframework/telemetry-utils\";\nimport { ISequencedDocumentMessage } from \"@fluidframework/protocol-definitions\";\nimport { IDeltasFetchResult, IStream, IStreamResult } from \"@fluidframework/driver-definitions\";\nimport { getRetryDelayFromError, canRetryOnError, createGenericNetworkError } from \"./network\";\nimport { logNetworkFailure } from \"./networkUtils\";\n// For now, this package is versioned and released in unison with the specific drivers\nimport { pkgVersion as driverVersion } from \"./packageVersion\";\nimport { calculateMaxWaitTime } from \"./runWithRetry\";\n\n// We double this value in first try in when we calculate time to wait for in \"calculateMaxWaitTime\" function.\nconst MissingFetchDelayInMs = 50;\n\ntype WorkingState = \"working\" | \"done\" | \"canceled\";\n\n/**\n * Helper class to organize parallel fetching of data\n * It can be used to concurrently do many requests, while consuming\n * data in the right order. Take a look at UT for examples.\n * @param concurrency - level of concurrency\n * @param from - starting point of fetching data (inclusive)\n * @param to - ending point of fetching data. exclusive, or undefined if unknown\n * @param payloadSize - batch size\n * @param logger - logger to use\n * @param requestCallback - callback to request batches\n * @returns Queue that can be used to retrieve data\n * @public\n */\nexport class ParallelRequests<T> {\n\tprivate latestRequested: number;\n\tprivate nextToDeliver: number;\n\tprivate readonly results = new Map<number, T[]>();\n\tprivate workingState: WorkingState = \"working\";\n\tprivate requestsInFlight = 0;\n\tprivate readonly endEvent = new Deferred<void>();\n\tprivate requests = 0;\n\tprivate readonly knewTo: boolean;\n\n\tprivate get working() {\n\t\treturn this.workingState === \"working\";\n\t}\n\tpublic get canceled() {\n\t\treturn this.workingState === \"canceled\";\n\t}\n\n\tconstructor(\n\t\tfrom: number,\n\t\tprivate to: number | undefined,\n\t\tprivate readonly payloadSize: number,\n\t\tprivate readonly logger: ITelemetryLoggerExt,\n\t\tprivate readonly requestCallback: (\n\t\t\trequest: number,\n\t\t\tfrom: number,\n\t\t\tto: number,\n\t\t\tstrongTo: boolean,\n\t\t\tprops: ITelemetryProperties,\n\t\t) => Promise<{ partial: boolean; cancel: boolean; payload: T[] }>,\n\t\tprivate readonly responseCallback: (payload: T[]) => void,\n\t) {\n\t\tthis.latestRequested = from;\n\t\tthis.nextToDeliver = from;\n\t\tthis.knewTo = to !== undefined;\n\t}\n\n\tpublic cancel() {\n\t\tif (this.working) {\n\t\t\tthis.workingState = \"canceled\";\n\t\t\tthis.endEvent.resolve();\n\t\t}\n\t}\n\n\tpublic async run(concurrency: number) {\n\t\tassert(concurrency > 0, 0x102 /* \"invalid level of concurrency\" */);\n\t\tassert(this.working, 0x103 /* \"trying to parallel run while not working\" */);\n\n\t\tlet c = concurrency;\n\t\twhile (c > 0) {\n\t\t\tc--;\n\t\t\tthis.addRequest();\n\t\t}\n\t\tthis.dispatch(); // will recalculate and trigger this.endEvent if needed\n\t\treturn this.endEvent.promise;\n\t}\n\n\tprivate done() {\n\t\t// We should satisfy request fully.\n\t\tassert(this.to !== undefined, 0x104 /* \"undefined end point for parallel fetch\" */);\n\t\tassert(\n\t\t\tthis.nextToDeliver >= this.to,\n\t\t\t0x105 /* \"unexpected end point for parallel fetch\" */,\n\t\t);\n\t\tif (this.working) {\n\t\t\tthis.workingState = \"done\";\n\t\t\tthis.endEvent.resolve();\n\t\t}\n\t}\n\n\tprivate fail(error) {\n\t\tif (this.working) {\n\t\t\tthis.workingState = \"done\";\n\t\t\tthis.endEvent.reject(error);\n\t\t}\n\t}\n\n\tprivate dispatch() {\n\t\twhile (this.working) {\n\t\t\tconst value = this.results.get(this.nextToDeliver);\n\t\t\tif (value === undefined) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tthis.results.delete(this.nextToDeliver);\n\t\t\tassert(\n\t\t\t\tvalue.length <= this.payloadSize,\n\t\t\t\t0x1d9 /* \"addRequestCore() should break into smaller chunks\" */,\n\t\t\t);\n\t\t\tthis.nextToDeliver += value.length;\n\t\t\tthis.responseCallback(value);\n\t\t}\n\n\t\t// Account for cancellation - state might be not in consistent state on cancelling operation\n\t\tif (this.working) {\n\t\t\tif (this.requestsInFlight === 0) {\n\t\t\t\t// we should have dispatched everything, no matter whether we knew about the end or not.\n\t\t\t\t// see comment in addRequestCore() around throwing away chunk if it's above this.to\n\t\t\t\tassert(\n\t\t\t\t\tthis.results.size === 0,\n\t\t\t\t\t0x107 /* \"ending dispatch with remaining results to be sent\" */,\n\t\t\t\t);\n\t\t\t\tthis.done();\n\t\t\t} else if (this.to !== undefined && this.nextToDeliver >= this.to) {\n\t\t\t\t// Learned about the end and dispatched all the ops up to it.\n\t\t\t\t// Ignore all the in-flight requests above boundary - unblock caller sooner.\n\t\t\t\tassert(\n\t\t\t\t\t!this.knewTo,\n\t\t\t\t\t0x108 /* \"ending results dispatch but knew in advance about more requests\" */,\n\t\t\t\t);\n\t\t\t\tthis.done();\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate getNextChunk() {\n\t\tif (!this.working) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tconst from = this.latestRequested;\n\t\tif (this.to !== undefined) {\n\t\t\tif (this.to <= from) {\n\t\t\t\treturn undefined;\n\t\t\t}\n\t\t}\n\n\t\t// this.latestRequested\n\t\t// inclusive on the right side! Exclusive on the left.\n\t\tthis.latestRequested += this.payloadSize;\n\n\t\tif (this.to !== undefined) {\n\t\t\tthis.latestRequested = Math.min(this.to, this.latestRequested);\n\t\t}\n\n\t\tassert(from < this.latestRequested, 0x109 /* \"unexpected next chunk position\" */);\n\n\t\treturn { from, to: this.latestRequested };\n\t}\n\n\tprivate addRequest() {\n\t\tconst chunk = this.getNextChunk();\n\t\tif (chunk === undefined) {\n\t\t\treturn;\n\t\t}\n\t\tthis.addRequestCore(chunk.from, chunk.to).catch(this.fail.bind(this));\n\t}\n\n\tprivate async addRequestCore(fromArg: number, toArg: number) {\n\t\tassert(this.working, 0x10a /* \"cannot add parallel request while not working\" */);\n\n\t\tlet from = fromArg;\n\t\tlet to = toArg;\n\n\t\t// to & from are exclusive\n\t\tthis.requestsInFlight++;\n\t\twhile (this.working) {\n\t\t\tconst requestedLength = to - from;\n\t\t\tassert(requestedLength > 0, 0x10b /* \"invalid parallel request range\" */);\n\n\t\t\t// We should not be wasting time asking for something useless.\n\t\t\tif (this.to !== undefined) {\n\t\t\t\tassert(from < this.to, 0x10c /* \"invalid parallel request start point\" */);\n\t\t\t\tassert(to <= this.to, 0x10d /* \"invalid parallel request end point\" */);\n\t\t\t}\n\n\t\t\tthis.requests++;\n\n\t\t\tconst promise = this.requestCallback(\n\t\t\t\tthis.requests,\n\t\t\t\tfrom,\n\t\t\t\tto,\n\t\t\t\tthis.to !== undefined,\n\t\t\t\t{},\n\t\t\t);\n\n\t\t\t// dispatch any prior received data\n\t\t\tthis.dispatch();\n\n\t\t\tconst { payload, cancel, partial } = await promise;\n\n\t\t\tif (cancel) {\n\t\t\t\tthis.cancel();\n\t\t\t}\n\n\t\t\tif (this.to !== undefined && from >= this.to) {\n\t\t\t\t// while we were waiting for response, we learned on what is the boundary\n\t\t\t\t// We can get here (with actual result!) if situation changed while this request was in\n\t\t\t\t// flight, i.e. the end was extended over what we learn in some other request\n\t\t\t\t// While it's useful not to throw this result, this is very corner cases and makes logic\n\t\t\t\t// (including consistency checks) much harder to write correctly.\n\t\t\t\t// So for now, we are throwing this result out the window.\n\t\t\t\tassert(\n\t\t\t\t\t!this.knewTo,\n\t\t\t\t\t0x10e /* \"should not throw result if we knew about boundary in advance\" */,\n\t\t\t\t);\n\t\t\t\t// Learn how often it happens and if it's too wasteful to throw these chunks.\n\t\t\t\t// If it pops into our view a lot, we would need to reconsider how we approach it.\n\t\t\t\t// Note that this is not visible to user other than potentially not hitting 100% of\n\t\t\t\t// what we can in perf domain.\n\t\t\t\tif (payload.length !== 0) {\n\t\t\t\t\tthis.logger.sendErrorEvent({\n\t\t\t\t\t\teventName: \"ParallelRequests_GotExtra\",\n\t\t\t\t\t\tfrom,\n\t\t\t\t\t\tto,\n\t\t\t\t\t\tend: this.to,\n\t\t\t\t\t\tlength: payload.length,\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tif (this.working) {\n\t\t\t\tconst fromOrig = from;\n\t\t\t\tconst length = payload.length;\n\t\t\t\tlet fullChunk = requestedLength <= length; // we can possible get more than we asked.\n\n\t\t\t\tif (length !== 0) {\n\t\t\t\t\t// We can get more than we asked for!\n\t\t\t\t\t// This can screw up logic in dispatch!\n\t\t\t\t\t// So push only batch size, and keep the rest for later - if conditions are favorable, we\n\t\t\t\t\t// will be able to use it. If not (parallel request overlapping these ops), it's easier to\n\t\t\t\t\t// discard them and wait for another (overlapping) request to come in later.\n\t\t\t\t\tif (requestedLength < length) {\n\t\t\t\t\t\t// This is error in a sense that it's not expected and likely points bug in other layer.\n\t\t\t\t\t\t// This layer copes with this situation just fine.\n\t\t\t\t\t\tthis.logger.sendTelemetryEvent({\n\t\t\t\t\t\t\teventName: \"ParallelRequests_Over\",\n\t\t\t\t\t\t\tfrom,\n\t\t\t\t\t\t\tto,\n\t\t\t\t\t\t\tlength,\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t\tconst data = payload.splice(0, requestedLength);\n\t\t\t\t\tthis.results.set(from, data);\n\t\t\t\t\tfrom += data.length;\n\t\t\t\t} else {\n\t\t\t\t\t// 1. empty (partial) chunks should not be returned by various caching / adapter layers -\n\t\t\t\t\t// they should fall back to next layer. This might be important invariant to hold to ensure\n\t\t\t\t\t// that we are less likely have bugs where such layer would keep returning empty partial\n\t\t\t\t\t// result on each call.\n\t\t\t\t\t// 2. Current invariant is that callback does retries until it gets something,\n\t\t\t\t\t// with the goal of failing if zero data is retrieved in given amount of time.\n\t\t\t\t\t// This is very specific property of storage / ops, so this logic is not here, but given only\n\t\t\t\t\t// one user of this class, we assert that to catch issues earlier.\n\t\t\t\t\t// These invariant can be relaxed if needed.\n\t\t\t\t\tassert(\n\t\t\t\t\t\t!partial,\n\t\t\t\t\t\t0x10f /* \"empty/partial chunks should not be returned by caching\" */,\n\t\t\t\t\t);\n\t\t\t\t\tassert(\n\t\t\t\t\t\t!this.knewTo,\n\t\t\t\t\t\t0x110 /* \"callback should retry until valid fetch before it learns new boundary\" */,\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\tif (!partial && !fullChunk) {\n\t\t\t\t\tif (!this.knewTo) {\n\t\t\t\t\t\tif (this.to === undefined || this.to > from) {\n\t\t\t\t\t\t\t// The END\n\t\t\t\t\t\t\tthis.to = from;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\t// We know that there are more items to be retrieved\n\t\t\t\t\t// Can we get partial chunk? Ideally storage indicates that's not a full chunk\n\t\t\t\t\t// Note that it's possible that not all ops hit storage yet.\n\t\t\t\t\t// We will come back to request more, and if we can't get any more ops soon, it's\n\t\t\t\t\t// catastrophic failure (see comment above on responsibility of callback to return something)\n\t\t\t\t\t// This layer will just keep trying until it gets full set.\n\t\t\t\t\tthis.logger.sendPerformanceEvent({\n\t\t\t\t\t\teventName: \"ParallelRequests_Partial\",\n\t\t\t\t\t\tfrom: fromOrig,\n\t\t\t\t\t\tto,\n\t\t\t\t\t\tlength,\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\tif (to === this.latestRequested) {\n\t\t\t\t\t// we can go after full chunk at the end if we received partial chunk, or more than asked\n\t\t\t\t\t// Also if we got more than we asked to, we can actually use those ops!\n\t\t\t\t\twhile (payload.length !== 0) {\n\t\t\t\t\t\tconst data = payload.splice(0, requestedLength);\n\t\t\t\t\t\tthis.results.set(from, data);\n\t\t\t\t\t\tfrom += data.length;\n\t\t\t\t\t}\n\n\t\t\t\t\tthis.latestRequested = from;\n\t\t\t\t\tfullChunk = true;\n\t\t\t\t}\n\n\t\t\t\tif (fullChunk) {\n\t\t\t\t\tconst chunk = this.getNextChunk();\n\t\t\t\t\tif (chunk === undefined) {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tfrom = chunk.from;\n\t\t\t\t\tto = chunk.to;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tthis.requestsInFlight--;\n\t\tthis.dispatch();\n\t}\n}\n\n/**\n * Helper queue class to allow async push / pull\n * It's essentially a pipe allowing multiple writers, and single reader\n * @public\n */\nexport class Queue<T> implements IStream<T> {\n\tprivate readonly queue: Promise<IStreamResult<T>>[] = [];\n\tprivate deferred: Deferred<IStreamResult<T>> | undefined;\n\tprivate done = false;\n\n\tpublic pushValue(value: T) {\n\t\tthis.pushCore(Promise.resolve({ done: false, value }));\n\t}\n\n\tpublic pushError(error: any) {\n\t\tthis.pushCore(Promise.reject(error));\n\t\tthis.done = true;\n\t}\n\n\tpublic pushDone() {\n\t\tthis.pushCore(Promise.resolve({ done: true }));\n\t\tthis.done = true;\n\t}\n\n\tprotected pushCore(value: Promise<IStreamResult<T>>) {\n\t\tassert(!this.done, 0x112 /* \"cannot push onto queue if done\" */);\n\t\tif (this.deferred) {\n\t\t\tassert(this.queue.length === 0, 0x113 /* \"deferred queue should be empty\" */);\n\t\t\tthis.deferred.resolve(value);\n\t\t\tthis.deferred = undefined;\n\t\t} else {\n\t\t\tthis.queue.push(value);\n\t\t}\n\t}\n\n\tpublic async read(): Promise<IStreamResult<T>> {\n\t\tassert(this.deferred === undefined, 0x114 /* \"cannot pop if deferred\" */);\n\t\tconst value = this.queue.shift();\n\t\tif (value !== undefined) {\n\t\t\treturn value;\n\t\t}\n\t\tassert(!this.done, 0x115 /* \"queue should not be done during pop\" */);\n\t\tthis.deferred = new Deferred<IStreamResult<T>>();\n\t\treturn this.deferred.promise;\n\t}\n}\n\nconst waitForOnline = async (): Promise<void> => {\n\t// Only wait if we have a strong signal that we're offline - otherwise assume we're online.\n\tif (globalThis.navigator?.onLine === false && globalThis.addEventListener !== undefined) {\n\t\treturn new Promise<void>((resolve) => {\n\t\t\tconst resolveAndRemoveListener = () => {\n\t\t\t\tresolve();\n\t\t\t\tglobalThis.removeEventListener(\"online\", resolveAndRemoveListener);\n\t\t\t};\n\t\t\tglobalThis.addEventListener(\"online\", resolveAndRemoveListener);\n\t\t});\n\t}\n};\n\n/**\n * Retrieve single batch of ops\n * @param request - request index\n * @param from - inclusive boundary\n * @param to - exclusive boundary\n * @param telemetryEvent - telemetry event used to track consecutive batch of requests\n * @param strongTo - tells if ops in range from...to have to be there and have to be retrieved.\n * If false, returning less ops would mean we reached end of file.\n * @param logger - logger object to use to log progress & errors\n * @param signal - cancelation signal\n * @param scenarioName - reason for fetching ops\n * @returns An object with resulting ops and cancellation / partial result flags\n */\nasync function getSingleOpBatch(\n\tget: (telemetryProps: ITelemetryProperties) => Promise<IDeltasFetchResult>,\n\tprops: ITelemetryProperties,\n\tstrongTo: boolean,\n\tlogger: ITelemetryLoggerExt,\n\tsignal?: AbortSignal,\n\tscenarioName?: string,\n): Promise<{ partial: boolean; cancel: boolean; payload: ISequencedDocumentMessage[] }> {\n\tlet lastSuccessTime: number | undefined;\n\tlet totalRetryAfterTime = 0;\n\tlet telemetryEvent: PerformanceEvent | undefined;\n\tlet retry: number = 0;\n\tconst nothing = { partial: false, cancel: true, payload: [] };\n\tlet waitStartTime: number = 0;\n\tlet waitTime = MissingFetchDelayInMs;\n\n\twhile (signal?.aborted !== true) {\n\t\tretry++;\n\t\tlet lastError: unknown;\n\t\tconst startTime = performance.now();\n\n\t\ttry {\n\t\t\t// Issue async request for deltas\n\t\t\tconst { messages, partialResult } = await get(\n\t\t\t\t{ ...props, retry } /* telemetry props */,\n\t\t\t);\n\n\t\t\t// If we got messages back, return them. Return regardless of whether we got messages back if we didn't\n\t\t\t// specify a \"to\", since we don't have an expectation of how many to receive.\n\t\t\tif (messages.length !== 0 || !strongTo) {\n\t\t\t\t// Report this event if we waited to fetch ops due to being offline or throttling.\n\t\t\t\ttelemetryEvent?.end({\n\t\t\t\t\tduration: totalRetryAfterTime,\n\t\t\t\t\t...props,\n\t\t\t\t\treason: scenarioName,\n\t\t\t\t});\n\t\t\t\treturn { payload: messages, cancel: false, partial: partialResult };\n\t\t\t}\n\n\t\t\t// Otherwise, the storage gave us back an empty set of ops but we were expecting a non-empty set.\n\n\t\t\tif (lastSuccessTime === undefined) {\n\t\t\t\t// Take timestamp of the first time server responded successfully, even though it wasn't with the ops we asked for.\n\t\t\t\t// If we keep getting empty responses we'll eventually fail out below.\n\t\t\t\tlastSuccessTime = performance.now();\n\t\t\t} else if (performance.now() - lastSuccessTime > 30000) {\n\t\t\t\t// If we are connected and receiving proper responses from server, but can't get any ops back,\n\t\t\t\t// then give up after some time. This likely indicates the issue with ordering service not flushing\n\t\t\t\t// ops to storage quick enough, and possibly waiting for summaries, while summarizer can't get\n\t\t\t\t// current as it can't get ops.\n\t\t\t\tthrow createGenericNetworkError(\n\t\t\t\t\t// pre-0.58 error message: failedToRetrieveOpsFromStorage:TooManyRetries\n\t\t\t\t\t\"Failed to retrieve ops from storage (Too Many Retries)\",\n\t\t\t\t\t{ canRetry: false },\n\t\t\t\t\t{\n\t\t\t\t\t\tretry,\n\t\t\t\t\t\tdriverVersion,\n\t\t\t\t\t\t...props,\n\t\t\t\t\t},\n\t\t\t\t);\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tlastError = error;\n\t\t\tconst canRetry = canRetryOnError(error);\n\n\t\t\tconst retryAfter = getRetryDelayFromError(error);\n\n\t\t\t// This will log to error table only if the error is non-retryable\n\t\t\tlogNetworkFailure(\n\t\t\t\tlogger,\n\t\t\t\t{\n\t\t\t\t\teventName: \"GetDeltas_Error\",\n\t\t\t\t\t...props,\n\t\t\t\t\tretry,\n\t\t\t\t\tduration: performance.now() - startTime,\n\t\t\t\t\tretryAfter,\n\t\t\t\t\treason: scenarioName,\n\t\t\t\t},\n\t\t\t\terror,\n\t\t\t);\n\n\t\t\tif (!canRetry) {\n\t\t\t\t// It's game over scenario.\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t}\n\n\t\tif (telemetryEvent === undefined) {\n\t\t\twaitStartTime = performance.now();\n\t\t\ttelemetryEvent = PerformanceEvent.start(logger, {\n\t\t\t\teventName: \"GetDeltasWaitTime\",\n\t\t\t});\n\t\t}\n\n\t\twaitTime = calculateMaxWaitTime(waitTime, lastError);\n\n\t\t// If we get here something has gone wrong - either got an unexpected empty set of messages back or a real error.\n\t\t// Either way we will wait a little bit before retrying.\n\t\tawait new Promise<void>((resolve) => {\n\t\t\tsetTimeout(resolve, waitTime);\n\t\t});\n\n\t\t// If we believe we're offline, we assume there's no point in trying until we at least think we're online.\n\t\t// NOTE: This isn't strictly true for drivers that don't require network (e.g. local driver). Really this logic\n\t\t// should probably live in the driver.\n\t\tawait waitForOnline();\n\t\ttotalRetryAfterTime += performance.now() - waitStartTime;\n\t}\n\n\treturn nothing;\n}\n\n/**\n * Request ops from storage\n * @param get - Getter callback to get individual batches\n * @param concurrency - Number of concurrent requests to make\n * @param fromTotal - starting sequence number to fetch (inclusive)\n * @param toTotal - max (exclusive) sequence number to fetch\n * @param payloadSize - Payload size\n * @param logger - Logger to log progress and errors\n * @param signal - Cancelation signal\n * @param scenarioName - Reason for fetching ops\n * @returns Messages fetched\n * @public\n */\nexport function requestOps(\n\tget: (\n\t\tfrom: number,\n\t\tto: number,\n\t\ttelemetryProps: ITelemetryProperties,\n\t) => Promise<IDeltasFetchResult>,\n\tconcurrency: number,\n\tfromTotal: number,\n\ttoTotal: number | undefined,\n\tpayloadSize: number,\n\tlogger: ITelemetryLoggerExt,\n\tsignal?: AbortSignal,\n\tscenarioName?: string,\n): IStream<ISequencedDocumentMessage[]> {\n\tlet requests = 0;\n\tlet lastFetch: number | undefined;\n\tlet length = 0;\n\tconst queue = new Queue<ISequencedDocumentMessage[]>();\n\n\tconst propsTotal: ITelemetryProperties = {\n\t\tfromTotal,\n\t\ttoTotal,\n\t};\n\n\tconst telemetryEvent = PerformanceEvent.start(logger, {\n\t\teventName: \"GetDeltas\",\n\t\t...propsTotal,\n\t\treason: scenarioName,\n\t});\n\n\tconst manager = new ParallelRequests<ISequencedDocumentMessage>(\n\t\tfromTotal,\n\t\ttoTotal,\n\t\tpayloadSize,\n\t\tlogger,\n\t\tasync (\n\t\t\trequest: number,\n\t\t\tfrom: number,\n\t\t\tto: number,\n\t\t\tstrongTo: boolean,\n\t\t\tpropsPerRequest: ITelemetryProperties,\n\t\t) => {\n\t\t\trequests++;\n\t\t\treturn getSingleOpBatch(\n\t\t\t\tasync (propsAll) => get(from, to, propsAll),\n\t\t\t\t{ request, from, to, ...propsTotal, ...propsPerRequest },\n\t\t\t\tstrongTo,\n\t\t\t\tlogger,\n\t\t\t\tsignal,\n\t\t\t\tscenarioName,\n\t\t\t);\n\t\t},\n\t\t(deltas: ISequencedDocumentMessage[]) => {\n\t\t\t// Assert continuing and right start.\n\t\t\tif (lastFetch === undefined) {\n\t\t\t\tassert(deltas[0].sequenceNumber === fromTotal, 0x26d /* \"wrong start\" */);\n\t\t\t} else {\n\t\t\t\tassert(deltas[0].sequenceNumber === lastFetch + 1, 0x26e /* \"wrong start\" */);\n\t\t\t}\n\t\t\tlastFetch = deltas[deltas.length - 1].sequenceNumber;\n\t\t\tassert(\n\t\t\t\tlastFetch - deltas[0].sequenceNumber + 1 === deltas.length,\n\t\t\t\t0x26f /* \"continuous and no duplicates\" */,\n\t\t\t);\n\t\t\tlength += deltas.length;\n\t\t\tqueue.pushValue(deltas);\n\t\t},\n\t);\n\n\t// Implement faster cancellation. getSingleOpBatch() checks signal, but only in between\n\t// waits (up to 10 seconds) and fetches (can take infinite amount of time).\n\t// While every such case should be improved and take into account signal (and thus cancel immediately),\n\t// it is beneficial to have catch-all\n\tconst listener = (event: Event) => {\n\t\tmanager.cancel();\n\t};\n\tif (signal !== undefined) {\n\t\tsignal.addEventListener(\"abort\", listener);\n\t}\n\n\tmanager\n\t\t.run(concurrency)\n\t\t.finally(() => {\n\t\t\tif (signal !== undefined) {\n\t\t\t\tsignal.removeEventListener(\"abort\", listener);\n\t\t\t}\n\t\t})\n\t\t.then(() => {\n\t\t\tconst props = {\n\t\t\t\tlastFetch,\n\t\t\t\tlength,\n\t\t\t\trequests,\n\t\t\t};\n\t\t\tif (manager.canceled) {\n\t\t\t\ttelemetryEvent.cancel({ ...props, error: \"ops request cancelled by client\" });\n\t\t\t} else {\n\t\t\t\tassert(\n\t\t\t\t\ttoTotal === undefined || (lastFetch !== undefined && lastFetch >= toTotal - 1),\n\t\t\t\t\t0x270 /* \"All requested ops fetched\" */,\n\t\t\t\t);\n\t\t\t\ttelemetryEvent.end(props);\n\t\t\t}\n\t\t\tqueue.pushDone();\n\t\t})\n\t\t.catch((error) => {\n\t\t\ttelemetryEvent.cancel(\n\t\t\t\t{\n\t\t\t\t\tlastFetch,\n\t\t\t\t\tlength,\n\t\t\t\t\trequests,\n\t\t\t\t},\n\t\t\t\terror,\n\t\t\t);\n\t\t\tqueue.pushError(error);\n\t\t});\n\n\treturn queue;\n}\n\n/**\n * @public\n */\nexport const emptyMessageStream: IStream<ISequencedDocumentMessage[]> = {\n\tread: async () => {\n\t\treturn { done: true };\n\t},\n};\n\n/**\n * @public\n */\nexport function streamFromMessages(\n\tmessagesArg: Promise<ISequencedDocumentMessage[]>,\n): IStream<ISequencedDocumentMessage[]> {\n\tlet messages: Promise<ISequencedDocumentMessage[]> | undefined = messagesArg;\n\treturn {\n\t\tread: async () => {\n\t\t\tif (messages === undefined) {\n\t\t\t\treturn { done: true };\n\t\t\t}\n\t\t\tconst value = await messages;\n\t\t\tmessages = undefined;\n\t\t\treturn value.length === 0 ? { done: true } : { done: false, value };\n\t\t},\n\t};\n}\n\n/**\n * @public\n */\nexport function streamObserver<T>(\n\tstream: IStream<T>,\n\thandler: (value: IStreamResult<T>) => void,\n): IStream<T> {\n\treturn {\n\t\tread: async () => {\n\t\t\tconst value = await stream.read();\n\t\t\thandler(value);\n\t\t\treturn value;\n\t\t},\n\t};\n}\n"]}
@@ -39,12 +39,14 @@ export interface IProgress {
39
39
  */
40
40
  export declare function runWithRetry<T>(api: (cancel?: AbortSignal) => Promise<T>, fetchCallName: string, logger: ITelemetryLoggerExt, progress: IProgress): Promise<T>;
41
41
  /**
42
- * In case endpoint(service or socket) is not reachable, then we maybe offline or may have got some transient error
43
- * not related to endpoint, in that case we want to try at faster pace and hence the max wait is lesser 8s as compared
44
- * to when endpoint is reachable in which case it is 30s.
45
- * @param error - error based on which we decide max wait time.
46
- * @returns Max wait time.
42
+ * Calculates time to wait for after an error based on the error and wait time for previous iteration.
43
+ * In case endpoint(service or socket) is not reachable, then we maybe offline or may have got some
44
+ * transient error not related to endpoint, in that case we want to try at faster pace and hence the
45
+ * max wait is lesser 8s as compared to when endpoint is reachable in which case it is 60s.
46
+ * @param delayMs - wait time for previous iteration
47
+ * @param error - error based on which we decide wait time.
48
+ * @returns Wait time to wait for.
47
49
  * @public
48
50
  */
49
- export declare function calculateMaxWaitTime(error: unknown): number;
51
+ export declare function calculateMaxWaitTime(delayMs: number, error: unknown): number;
50
52
  //# sourceMappingURL=runWithRetry.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"runWithRetry.d.ts","sourceRoot":"","sources":["../src/runWithRetry.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,mBAAmB,EAAgB,MAAM,iCAAiC,CAAC;AAQpF;;;;GAIG;AACH,MAAM,WAAW,SAAS;IACzB;;;;;;;;;;;;;OAaG;IACH,MAAM,CAAC,EAAE,WAAW,CAAC;IAErB;;;;;;;OAOG;IACH,OAAO,CAAC,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,GAAG,IAAI,CAAC;CAC9C;AAED;;GAEG;AACH,wBAAsB,YAAY,CAAC,CAAC,EACnC,GAAG,EAAE,CAAC,MAAM,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,CAAC,CAAC,EACzC,aAAa,EAAE,MAAM,EACrB,MAAM,EAAE,mBAAmB,EAC3B,QAAQ,EAAE,SAAS,GACjB,OAAO,CAAC,CAAC,CAAC,CAuFZ;AAKD;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAI3D"}
1
+ {"version":3,"file":"runWithRetry.d.ts","sourceRoot":"","sources":["../src/runWithRetry.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,mBAAmB,EAAgB,MAAM,iCAAiC,CAAC;AAQpF;;;;GAIG;AACH,MAAM,WAAW,SAAS;IACzB;;;;;;;;;;;;;OAaG;IACH,MAAM,CAAC,EAAE,WAAW,CAAC;IAErB;;;;;;;OAOG;IACH,OAAO,CAAC,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,GAAG,IAAI,CAAC;CAC9C;AAED;;GAEG;AACH,wBAAsB,YAAY,CAAC,CAAC,EACnC,GAAG,EAAE,CAAC,MAAM,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,CAAC,CAAC,EACzC,aAAa,EAAE,MAAM,EACrB,MAAM,EAAE,mBAAmB,EAC3B,QAAQ,EAAE,SAAS,GACjB,OAAO,CAAC,CAAC,CAAC,CAsFZ;AAKD;;;;;;;;;GASG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,MAAM,CAU5E"}
@@ -15,7 +15,8 @@ import { NonRetryableError } from ".";
15
15
  export async function runWithRetry(api, fetchCallName, logger, progress) {
16
16
  let result;
17
17
  let success = false;
18
- let retryAfterMs = 1000; // has to be positive!
18
+ // We double this value in first try in when we calculate time to wait for in "calculateMaxWaitTime" function.
19
+ let retryAfterMs = 500; // has to be positive!
19
20
  let numRetries = 0;
20
21
  const startTime = performance.now();
21
22
  let lastError;
@@ -61,10 +62,8 @@ export async function runWithRetry(api, fetchCallName, logger, progress) {
61
62
  }
62
63
  numRetries++;
63
64
  lastError = err;
64
- // If the error is throttling error, then wait for the specified time before retrying.
65
- retryAfterMs =
66
- getRetryDelayFromError(err) ??
67
- Math.min(retryAfterMs * 2, calculateMaxWaitTime(err));
65
+ // Wait for the calculated time before retrying.
66
+ retryAfterMs = calculateMaxWaitTime(retryAfterMs, err);
68
67
  if (progress.onRetry) {
69
68
  progress.onRetry(retryAfterMs, err);
70
69
  }
@@ -82,19 +81,24 @@ export async function runWithRetry(api, fetchCallName, logger, progress) {
82
81
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
83
82
  return result;
84
83
  }
85
- const MaxReconnectDelayInMsWhenEndpointIsReachable = 30000;
84
+ const MaxReconnectDelayInMsWhenEndpointIsReachable = 60000;
86
85
  const MaxReconnectDelayInMsWhenEndpointIsNotReachable = 8000;
87
86
  /**
88
- * In case endpoint(service or socket) is not reachable, then we maybe offline or may have got some transient error
89
- * not related to endpoint, in that case we want to try at faster pace and hence the max wait is lesser 8s as compared
90
- * to when endpoint is reachable in which case it is 30s.
91
- * @param error - error based on which we decide max wait time.
92
- * @returns Max wait time.
87
+ * Calculates time to wait for after an error based on the error and wait time for previous iteration.
88
+ * In case endpoint(service or socket) is not reachable, then we maybe offline or may have got some
89
+ * transient error not related to endpoint, in that case we want to try at faster pace and hence the
90
+ * max wait is lesser 8s as compared to when endpoint is reachable in which case it is 60s.
91
+ * @param delayMs - wait time for previous iteration
92
+ * @param error - error based on which we decide wait time.
93
+ * @returns Wait time to wait for.
93
94
  * @public
94
95
  */
95
- export function calculateMaxWaitTime(error) {
96
- return isFluidError(error) && error.getTelemetryProperties().endpointReached === true
96
+ export function calculateMaxWaitTime(delayMs, error) {
97
+ const retryDelayFromError = getRetryDelayFromError(error);
98
+ let newDelayMs = Math.max(retryDelayFromError ?? 0, delayMs * 2);
99
+ newDelayMs = Math.min(delayMs, isFluidError(error) && error.getTelemetryProperties().endpointReached === true
97
100
  ? MaxReconnectDelayInMsWhenEndpointIsReachable
98
- : MaxReconnectDelayInMsWhenEndpointIsNotReachable;
101
+ : MaxReconnectDelayInMsWhenEndpointIsNotReachable);
102
+ return newDelayMs;
99
103
  }
100
104
  //# sourceMappingURL=runWithRetry.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"runWithRetry.js","sourceRoot":"","sources":["../src/runWithRetry.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { ITelemetryLoggerExt, isFluidError } from \"@fluidframework/telemetry-utils\";\nimport { performance } from \"@fluid-internal/client-utils\";\nimport { delay } from \"@fluidframework/core-utils\";\nimport { DriverErrorTypes } from \"@fluidframework/driver-definitions\";\nimport { canRetryOnError, getRetryDelayFromError } from \"./network\";\nimport { pkgVersion } from \"./packageVersion\";\nimport { NonRetryableError } from \".\";\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 * @public\n */\nexport interface IProgress {\n\t/**\n\t * Abort signal used to cancel operation.\n\t *\n\t * @remarks Note that most of the layers do not use this signal yet. We need to change that over time.\n\t * Please consult with API documentation / implementation.\n\t * Note that number of layers may not check this signal while holding this request in a queue,\n\t * so it may take a while it takes effect. This can be improved in the future.\n\t *\n\t * The layers in question are:\n\t *\n\t * - driver (RateLimiter)\n\t *\n\t * - runWithRetry\n\t */\n\tcancel?: AbortSignal;\n\n\t/**\n\t * Called whenever api returns cancellable error and the call is going to be retried.\n\t * Any exception thrown from this call back result in cancellation of operation\n\t * and propagation of thrown exception.\n\t * @param delayInMs - delay before next retry. This value will depend on internal back-off logic,\n\t * as well as information provided by service (like 429 error asking to wait for some time before retry)\n\t * @param error - error object returned from the call.\n\t */\n\tonRetry?(delayInMs: number, error: any): void;\n}\n\n/**\n * @public\n */\nexport async function runWithRetry<T>(\n\tapi: (cancel?: AbortSignal) => Promise<T>,\n\tfetchCallName: string,\n\tlogger: ITelemetryLoggerExt,\n\tprogress: IProgress,\n): Promise<T> {\n\tlet result: T | undefined;\n\tlet success = false;\n\tlet retryAfterMs = 1000; // has to be positive!\n\tlet numRetries = 0;\n\tconst startTime = performance.now();\n\tlet lastError: any;\n\tdo {\n\t\ttry {\n\t\t\tresult = await api(progress.cancel);\n\t\t\tsuccess = true;\n\t\t} catch (err) {\n\t\t\t// If it is not retriable, then just throw the error.\n\t\t\tif (!canRetryOnError(err)) {\n\t\t\t\tlogger.sendTelemetryEvent(\n\t\t\t\t\t{\n\t\t\t\t\t\teventName: `${fetchCallName}_cancel`,\n\t\t\t\t\t\tretry: numRetries,\n\t\t\t\t\t\tduration: performance.now() - startTime,\n\t\t\t\t\t\tfetchCallName,\n\t\t\t\t\t},\n\t\t\t\t\terr,\n\t\t\t\t);\n\t\t\t\tthrow err;\n\t\t\t}\n\n\t\t\tif (progress.cancel?.aborted === true) {\n\t\t\t\tlogger.sendTelemetryEvent(\n\t\t\t\t\t{\n\t\t\t\t\t\teventName: `${fetchCallName}_runWithRetryAborted`,\n\t\t\t\t\t\tretry: numRetries,\n\t\t\t\t\t\tduration: performance.now() - startTime,\n\t\t\t\t\t\tfetchCallName,\n\t\t\t\t\t\treason: progress.cancel.reason,\n\t\t\t\t\t},\n\t\t\t\t\terr,\n\t\t\t\t);\n\t\t\t\tthrow new NonRetryableError(\n\t\t\t\t\t\"runWithRetry was Aborted\",\n\t\t\t\t\tDriverErrorTypes.genericError,\n\t\t\t\t\t{\n\t\t\t\t\t\tdriverVersion: pkgVersion,\n\t\t\t\t\t\tfetchCallName,\n\t\t\t\t\t\treason: progress.cancel.reason,\n\t\t\t\t\t},\n\t\t\t\t);\n\t\t\t}\n\n\t\t\t// logging the first failed retry instead of every attempt. We want to avoid filling telemetry\n\t\t\t// when we have tight loop of retrying in offline mode, but we also want to know what caused\n\t\t\t// the failure in the first place\n\t\t\tif (numRetries === 0) {\n\t\t\t\tlogger.sendTelemetryEvent(\n\t\t\t\t\t{\n\t\t\t\t\t\teventName: `${fetchCallName}_firstFailed`,\n\t\t\t\t\t\tduration: performance.now() - startTime,\n\t\t\t\t\t\tfetchCallName,\n\t\t\t\t\t},\n\t\t\t\t\terr,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tnumRetries++;\n\t\t\tlastError = err;\n\t\t\t// If the error is throttling error, then wait for the specified time before retrying.\n\t\t\tretryAfterMs =\n\t\t\t\tgetRetryDelayFromError(err) ??\n\t\t\t\tMath.min(retryAfterMs * 2, calculateMaxWaitTime(err));\n\t\t\tif (progress.onRetry) {\n\t\t\t\tprogress.onRetry(retryAfterMs, err);\n\t\t\t}\n\t\t\tawait delay(retryAfterMs);\n\t\t}\n\t} while (!success);\n\tif (numRetries > 0) {\n\t\tlogger.sendTelemetryEvent(\n\t\t\t{\n\t\t\t\teventName: `${fetchCallName}_lastError`,\n\t\t\t\tretry: numRetries,\n\t\t\t\tduration: performance.now() - startTime,\n\t\t\t\tfetchCallName,\n\t\t\t},\n\t\t\tlastError,\n\t\t);\n\t}\n\t// eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n\treturn result!;\n}\n\nconst MaxReconnectDelayInMsWhenEndpointIsReachable = 30000;\nconst MaxReconnectDelayInMsWhenEndpointIsNotReachable = 8000;\n\n/**\n * In case endpoint(service or socket) is not reachable, then we maybe offline or may have got some transient error\n * not related to endpoint, in that case we want to try at faster pace and hence the max wait is lesser 8s as compared\n * to when endpoint is reachable in which case it is 30s.\n * @param error - error based on which we decide max wait time.\n * @returns Max wait time.\n * @public\n */\nexport function calculateMaxWaitTime(error: unknown): number {\n\treturn isFluidError(error) && error.getTelemetryProperties().endpointReached === true\n\t\t? MaxReconnectDelayInMsWhenEndpointIsReachable\n\t\t: MaxReconnectDelayInMsWhenEndpointIsNotReachable;\n}\n"]}
1
+ {"version":3,"file":"runWithRetry.js","sourceRoot":"","sources":["../src/runWithRetry.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { ITelemetryLoggerExt, isFluidError } from \"@fluidframework/telemetry-utils\";\nimport { performance } from \"@fluid-internal/client-utils\";\nimport { delay } from \"@fluidframework/core-utils\";\nimport { DriverErrorTypes } from \"@fluidframework/driver-definitions\";\nimport { canRetryOnError, getRetryDelayFromError } from \"./network\";\nimport { pkgVersion } from \"./packageVersion\";\nimport { NonRetryableError } from \".\";\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 * @public\n */\nexport interface IProgress {\n\t/**\n\t * Abort signal used to cancel operation.\n\t *\n\t * @remarks Note that most of the layers do not use this signal yet. We need to change that over time.\n\t * Please consult with API documentation / implementation.\n\t * Note that number of layers may not check this signal while holding this request in a queue,\n\t * so it may take a while it takes effect. This can be improved in the future.\n\t *\n\t * The layers in question are:\n\t *\n\t * - driver (RateLimiter)\n\t *\n\t * - runWithRetry\n\t */\n\tcancel?: AbortSignal;\n\n\t/**\n\t * Called whenever api returns cancellable error and the call is going to be retried.\n\t * Any exception thrown from this call back result in cancellation of operation\n\t * and propagation of thrown exception.\n\t * @param delayInMs - delay before next retry. This value will depend on internal back-off logic,\n\t * as well as information provided by service (like 429 error asking to wait for some time before retry)\n\t * @param error - error object returned from the call.\n\t */\n\tonRetry?(delayInMs: number, error: any): void;\n}\n\n/**\n * @public\n */\nexport async function runWithRetry<T>(\n\tapi: (cancel?: AbortSignal) => Promise<T>,\n\tfetchCallName: string,\n\tlogger: ITelemetryLoggerExt,\n\tprogress: IProgress,\n): Promise<T> {\n\tlet result: T | undefined;\n\tlet success = false;\n\t// We double this value in first try in when we calculate time to wait for in \"calculateMaxWaitTime\" function.\n\tlet retryAfterMs = 500; // has to be positive!\n\tlet numRetries = 0;\n\tconst startTime = performance.now();\n\tlet lastError: any;\n\tdo {\n\t\ttry {\n\t\t\tresult = await api(progress.cancel);\n\t\t\tsuccess = true;\n\t\t} catch (err) {\n\t\t\t// If it is not retriable, then just throw the error.\n\t\t\tif (!canRetryOnError(err)) {\n\t\t\t\tlogger.sendTelemetryEvent(\n\t\t\t\t\t{\n\t\t\t\t\t\teventName: `${fetchCallName}_cancel`,\n\t\t\t\t\t\tretry: numRetries,\n\t\t\t\t\t\tduration: performance.now() - startTime,\n\t\t\t\t\t\tfetchCallName,\n\t\t\t\t\t},\n\t\t\t\t\terr,\n\t\t\t\t);\n\t\t\t\tthrow err;\n\t\t\t}\n\n\t\t\tif (progress.cancel?.aborted === true) {\n\t\t\t\tlogger.sendTelemetryEvent(\n\t\t\t\t\t{\n\t\t\t\t\t\teventName: `${fetchCallName}_runWithRetryAborted`,\n\t\t\t\t\t\tretry: numRetries,\n\t\t\t\t\t\tduration: performance.now() - startTime,\n\t\t\t\t\t\tfetchCallName,\n\t\t\t\t\t\treason: progress.cancel.reason,\n\t\t\t\t\t},\n\t\t\t\t\terr,\n\t\t\t\t);\n\t\t\t\tthrow new NonRetryableError(\n\t\t\t\t\t\"runWithRetry was Aborted\",\n\t\t\t\t\tDriverErrorTypes.genericError,\n\t\t\t\t\t{\n\t\t\t\t\t\tdriverVersion: pkgVersion,\n\t\t\t\t\t\tfetchCallName,\n\t\t\t\t\t\treason: progress.cancel.reason,\n\t\t\t\t\t},\n\t\t\t\t);\n\t\t\t}\n\n\t\t\t// logging the first failed retry instead of every attempt. We want to avoid filling telemetry\n\t\t\t// when we have tight loop of retrying in offline mode, but we also want to know what caused\n\t\t\t// the failure in the first place\n\t\t\tif (numRetries === 0) {\n\t\t\t\tlogger.sendTelemetryEvent(\n\t\t\t\t\t{\n\t\t\t\t\t\teventName: `${fetchCallName}_firstFailed`,\n\t\t\t\t\t\tduration: performance.now() - startTime,\n\t\t\t\t\t\tfetchCallName,\n\t\t\t\t\t},\n\t\t\t\t\terr,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tnumRetries++;\n\t\t\tlastError = err;\n\t\t\t// Wait for the calculated time before retrying.\n\t\t\tretryAfterMs = calculateMaxWaitTime(retryAfterMs, err);\n\t\t\tif (progress.onRetry) {\n\t\t\t\tprogress.onRetry(retryAfterMs, err);\n\t\t\t}\n\t\t\tawait delay(retryAfterMs);\n\t\t}\n\t} while (!success);\n\tif (numRetries > 0) {\n\t\tlogger.sendTelemetryEvent(\n\t\t\t{\n\t\t\t\teventName: `${fetchCallName}_lastError`,\n\t\t\t\tretry: numRetries,\n\t\t\t\tduration: performance.now() - startTime,\n\t\t\t\tfetchCallName,\n\t\t\t},\n\t\t\tlastError,\n\t\t);\n\t}\n\t// eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n\treturn result!;\n}\n\nconst MaxReconnectDelayInMsWhenEndpointIsReachable = 60000;\nconst MaxReconnectDelayInMsWhenEndpointIsNotReachable = 8000;\n\n/**\n * Calculates time to wait for after an error based on the error and wait time for previous iteration.\n * In case endpoint(service or socket) is not reachable, then we maybe offline or may have got some\n * transient error not related to endpoint, in that case we want to try at faster pace and hence the\n * max wait is lesser 8s as compared to when endpoint is reachable in which case it is 60s.\n * @param delayMs - wait time for previous iteration\n * @param error - error based on which we decide wait time.\n * @returns Wait time to wait for.\n * @public\n */\nexport function calculateMaxWaitTime(delayMs: number, error: unknown): number {\n\tconst retryDelayFromError = getRetryDelayFromError(error);\n\tlet newDelayMs = Math.max(retryDelayFromError ?? 0, delayMs * 2);\n\tnewDelayMs = Math.min(\n\t\tdelayMs,\n\t\tisFluidError(error) && error.getTelemetryProperties().endpointReached === true\n\t\t\t? MaxReconnectDelayInMsWhenEndpointIsReachable\n\t\t\t: MaxReconnectDelayInMsWhenEndpointIsNotReachable,\n\t);\n\treturn newDelayMs;\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fluidframework/driver-utils",
3
- "version": "2.0.0-internal.7.2.1",
3
+ "version": "2.0.0-internal.7.3.0",
4
4
  "description": "Collection of utility functions for Fluid drivers",
5
5
  "homepage": "https://fluidframework.com",
6
6
  "repository": {
@@ -35,27 +35,27 @@
35
35
  "temp-directory": "nyc/.nyc_output"
36
36
  },
37
37
  "dependencies": {
38
- "@fluid-internal/client-utils": ">=2.0.0-internal.7.2.1 <2.0.0-internal.7.3.0",
39
- "@fluidframework/core-interfaces": ">=2.0.0-internal.7.2.1 <2.0.0-internal.7.3.0",
40
- "@fluidframework/core-utils": ">=2.0.0-internal.7.2.1 <2.0.0-internal.7.3.0",
41
- "@fluidframework/driver-definitions": ">=2.0.0-internal.7.2.1 <2.0.0-internal.7.3.0",
38
+ "@fluid-internal/client-utils": ">=2.0.0-internal.7.3.0 <2.0.0-internal.7.4.0",
39
+ "@fluidframework/core-interfaces": ">=2.0.0-internal.7.3.0 <2.0.0-internal.7.4.0",
40
+ "@fluidframework/core-utils": ">=2.0.0-internal.7.3.0 <2.0.0-internal.7.4.0",
41
+ "@fluidframework/driver-definitions": ">=2.0.0-internal.7.3.0 <2.0.0-internal.7.4.0",
42
42
  "@fluidframework/gitresources": "^2.0.1",
43
43
  "@fluidframework/protocol-base": "^2.0.1",
44
44
  "@fluidframework/protocol-definitions": "^3.0.0",
45
- "@fluidframework/telemetry-utils": ">=2.0.0-internal.7.2.1 <2.0.0-internal.7.3.0",
45
+ "@fluidframework/telemetry-utils": ">=2.0.0-internal.7.3.0 <2.0.0-internal.7.4.0",
46
46
  "axios": "^0.26.0",
47
47
  "lz4js": "^0.2.0",
48
48
  "url": "^0.11.0",
49
49
  "uuid": "^9.0.0"
50
50
  },
51
51
  "devDependencies": {
52
- "@fluid-tools/build-cli": "^0.26.1",
52
+ "@fluid-tools/build-cli": "^0.28.0",
53
53
  "@fluidframework/build-common": "^2.0.3",
54
- "@fluidframework/build-tools": "^0.26.1",
55
- "@fluidframework/driver-utils-previous": "npm:@fluidframework/driver-utils@2.0.0-internal.7.1.0",
56
- "@fluidframework/eslint-config-fluid": "^3.0.0",
57
- "@fluidframework/mocha-test-setup": ">=2.0.0-internal.7.2.1 <2.0.0-internal.7.3.0",
58
- "@microsoft/api-extractor": "^7.37.0",
54
+ "@fluidframework/build-tools": "^0.28.0",
55
+ "@fluidframework/driver-utils-previous": "npm:@fluidframework/driver-utils@2.0.0-internal.7.2.0",
56
+ "@fluidframework/eslint-config-fluid": "^3.1.0",
57
+ "@fluidframework/mocha-test-setup": ">=2.0.0-internal.7.3.0 <2.0.0-internal.7.4.0",
58
+ "@microsoft/api-extractor": "^7.38.3",
59
59
  "@types/mocha": "^9.1.1",
60
60
  "@types/node": "^16.18.38",
61
61
  "@types/sinon": "^7.0.13",
@@ -83,7 +83,7 @@
83
83
  "build:genver": "gen-version",
84
84
  "build:test": "tsc --project ./src/test/tsconfig.json",
85
85
  "ci:build:docs": "api-extractor run",
86
- "clean": "rimraf --glob dist lib \"*.tsbuildinfo\" \"*.build.log\" _api-extractor-temp nyc",
86
+ "clean": "rimraf --glob dist lib \"**/*.tsbuildinfo\" \"**/*.build.log\" _api-extractor-temp nyc",
87
87
  "eslint": "eslint --format stylish src",
88
88
  "eslint:fix": "eslint --format stylish src --fix --fix-type problem,suggestion,layout",
89
89
  "format": "npm run prettier:fix",
@@ -93,7 +93,7 @@
93
93
  "prettier:fix": "prettier --write . --ignore-path ../../../.prettierignore",
94
94
  "test": "npm run test:mocha",
95
95
  "test:coverage": "c8 npm test",
96
- "test:mocha": "mocha --ignore 'dist/test/types/*' --recursive dist/test -r node_modules/@fluidframework/mocha-test-setup",
96
+ "test:mocha": "mocha --ignore \"dist/test/types/*\" --recursive dist/test -r node_modules/@fluidframework/mocha-test-setup",
97
97
  "test:mocha:verbose": "cross-env FLUID_TEST_VERBOSE=1 npm run test:mocha",
98
98
  "tsc": "tsc",
99
99
  "typetests:gen": "fluid-type-test-generator",
@@ -6,4 +6,4 @@
6
6
  */
7
7
 
8
8
  export const pkgName = "@fluidframework/driver-utils";
9
- export const pkgVersion = "2.0.0-internal.7.2.1";
9
+ export const pkgVersion = "2.0.0-internal.7.3.0";
@@ -12,9 +12,10 @@ import { getRetryDelayFromError, canRetryOnError, createGenericNetworkError } fr
12
12
  import { logNetworkFailure } from "./networkUtils";
13
13
  // For now, this package is versioned and released in unison with the specific drivers
14
14
  import { pkgVersion as driverVersion } from "./packageVersion";
15
+ import { calculateMaxWaitTime } from "./runWithRetry";
15
16
 
16
- const MaxFetchDelayInMs = 10000;
17
- const MissingFetchDelayInMs = 100;
17
+ // We double this value in first try in when we calculate time to wait for in "calculateMaxWaitTime" function.
18
+ const MissingFetchDelayInMs = 50;
18
19
 
19
20
  type WorkingState = "working" | "done" | "canceled";
20
21
 
@@ -423,10 +424,11 @@ async function getSingleOpBatch(
423
424
  let retry: number = 0;
424
425
  const nothing = { partial: false, cancel: true, payload: [] };
425
426
  let waitStartTime: number = 0;
427
+ let waitTime = MissingFetchDelayInMs;
426
428
 
427
429
  while (signal?.aborted !== true) {
428
430
  retry++;
429
- let delay = Math.min(MaxFetchDelayInMs, MissingFetchDelayInMs * Math.pow(2, retry));
431
+ let lastError: unknown;
430
432
  const startTime = performance.now();
431
433
 
432
434
  try {
@@ -470,6 +472,7 @@ async function getSingleOpBatch(
470
472
  );
471
473
  }
472
474
  } catch (error) {
475
+ lastError = error;
473
476
  const canRetry = canRetryOnError(error);
474
477
 
475
478
  const retryAfter = getRetryDelayFromError(error);
@@ -492,11 +495,6 @@ async function getSingleOpBatch(
492
495
  // It's game over scenario.
493
496
  throw error;
494
497
  }
495
-
496
- if (retryAfter !== undefined) {
497
- // If the error told us to wait, then we will wait for that specific amount rather than the default.
498
- delay = retryAfter;
499
- }
500
498
  }
501
499
 
502
500
  if (telemetryEvent === undefined) {
@@ -506,10 +504,12 @@ async function getSingleOpBatch(
506
504
  });
507
505
  }
508
506
 
507
+ waitTime = calculateMaxWaitTime(waitTime, lastError);
508
+
509
509
  // If we get here something has gone wrong - either got an unexpected empty set of messages back or a real error.
510
510
  // Either way we will wait a little bit before retrying.
511
511
  await new Promise<void>((resolve) => {
512
- setTimeout(resolve, delay);
512
+ setTimeout(resolve, waitTime);
513
513
  });
514
514
 
515
515
  // If we believe we're offline, we assume there's no point in trying until we at least think we're online.
@@ -55,7 +55,8 @@ export async function runWithRetry<T>(
55
55
  ): Promise<T> {
56
56
  let result: T | undefined;
57
57
  let success = false;
58
- let retryAfterMs = 1000; // has to be positive!
58
+ // We double this value in first try in when we calculate time to wait for in "calculateMaxWaitTime" function.
59
+ let retryAfterMs = 500; // has to be positive!
59
60
  let numRetries = 0;
60
61
  const startTime = performance.now();
61
62
  let lastError: any;
@@ -116,10 +117,8 @@ export async function runWithRetry<T>(
116
117
 
117
118
  numRetries++;
118
119
  lastError = err;
119
- // If the error is throttling error, then wait for the specified time before retrying.
120
- retryAfterMs =
121
- getRetryDelayFromError(err) ??
122
- Math.min(retryAfterMs * 2, calculateMaxWaitTime(err));
120
+ // Wait for the calculated time before retrying.
121
+ retryAfterMs = calculateMaxWaitTime(retryAfterMs, err);
123
122
  if (progress.onRetry) {
124
123
  progress.onRetry(retryAfterMs, err);
125
124
  }
@@ -141,19 +140,27 @@ export async function runWithRetry<T>(
141
140
  return result!;
142
141
  }
143
142
 
144
- const MaxReconnectDelayInMsWhenEndpointIsReachable = 30000;
143
+ const MaxReconnectDelayInMsWhenEndpointIsReachable = 60000;
145
144
  const MaxReconnectDelayInMsWhenEndpointIsNotReachable = 8000;
146
145
 
147
146
  /**
148
- * In case endpoint(service or socket) is not reachable, then we maybe offline or may have got some transient error
149
- * not related to endpoint, in that case we want to try at faster pace and hence the max wait is lesser 8s as compared
150
- * to when endpoint is reachable in which case it is 30s.
151
- * @param error - error based on which we decide max wait time.
152
- * @returns Max wait time.
147
+ * Calculates time to wait for after an error based on the error and wait time for previous iteration.
148
+ * In case endpoint(service or socket) is not reachable, then we maybe offline or may have got some
149
+ * transient error not related to endpoint, in that case we want to try at faster pace and hence the
150
+ * max wait is lesser 8s as compared to when endpoint is reachable in which case it is 60s.
151
+ * @param delayMs - wait time for previous iteration
152
+ * @param error - error based on which we decide wait time.
153
+ * @returns Wait time to wait for.
153
154
  * @public
154
155
  */
155
- export function calculateMaxWaitTime(error: unknown): number {
156
- return isFluidError(error) && error.getTelemetryProperties().endpointReached === true
157
- ? MaxReconnectDelayInMsWhenEndpointIsReachable
158
- : MaxReconnectDelayInMsWhenEndpointIsNotReachable;
156
+ export function calculateMaxWaitTime(delayMs: number, error: unknown): number {
157
+ const retryDelayFromError = getRetryDelayFromError(error);
158
+ let newDelayMs = Math.max(retryDelayFromError ?? 0, delayMs * 2);
159
+ newDelayMs = Math.min(
160
+ delayMs,
161
+ isFluidError(error) && error.getTelemetryProperties().endpointReached === true
162
+ ? MaxReconnectDelayInMsWhenEndpointIsReachable
163
+ : MaxReconnectDelayInMsWhenEndpointIsNotReachable,
164
+ );
165
+ return newDelayMs;
159
166
  }