@fluidframework/container-loader 2.0.0-dev.5.3.2.178189 → 2.0.0-dev.6.4.0.191258
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 +131 -0
- package/README.md +10 -6
- package/dist/audience.d.ts +1 -0
- package/dist/audience.d.ts.map +1 -1
- package/dist/audience.js +5 -3
- package/dist/audience.js.map +1 -1
- package/dist/catchUpMonitor.js +2 -2
- package/dist/catchUpMonitor.js.map +1 -1
- package/dist/connectionManager.d.ts +5 -5
- package/dist/connectionManager.d.ts.map +1 -1
- package/dist/connectionManager.js +97 -93
- package/dist/connectionManager.js.map +1 -1
- package/dist/connectionStateHandler.d.ts +15 -14
- package/dist/connectionStateHandler.d.ts.map +1 -1
- package/dist/connectionStateHandler.js +50 -52
- package/dist/connectionStateHandler.js.map +1 -1
- package/dist/container.d.ts +20 -9
- package/dist/container.d.ts.map +1 -1
- package/dist/container.js +327 -277
- package/dist/container.js.map +1 -1
- package/dist/containerContext.d.ts +2 -7
- package/dist/containerContext.d.ts.map +1 -1
- package/dist/containerContext.js +2 -14
- package/dist/containerContext.js.map +1 -1
- package/dist/containerStorageAdapter.d.ts.map +1 -1
- package/dist/containerStorageAdapter.js +12 -13
- package/dist/containerStorageAdapter.js.map +1 -1
- package/dist/contracts.d.ts +21 -8
- package/dist/contracts.d.ts.map +1 -1
- package/dist/contracts.js +3 -3
- package/dist/contracts.js.map +1 -1
- package/dist/debugLogger.d.ts +30 -0
- package/dist/debugLogger.d.ts.map +1 -0
- package/dist/debugLogger.js +95 -0
- package/dist/debugLogger.js.map +1 -0
- package/dist/deltaManager.d.ts +21 -10
- package/dist/deltaManager.d.ts.map +1 -1
- package/dist/deltaManager.js +114 -66
- package/dist/deltaManager.js.map +1 -1
- package/dist/deltaQueue.d.ts +1 -1
- package/dist/deltaQueue.d.ts.map +1 -1
- package/dist/deltaQueue.js +10 -10
- package/dist/deltaQueue.js.map +1 -1
- package/dist/disposal.d.ts +2 -2
- package/dist/disposal.d.ts.map +1 -1
- package/dist/disposal.js +1 -1
- package/dist/disposal.js.map +1 -1
- package/dist/error.d.ts +23 -0
- package/dist/error.d.ts.map +1 -0
- package/dist/error.js +32 -0
- package/dist/error.js.map +1 -0
- package/dist/loader.d.ts +22 -3
- package/dist/loader.d.ts.map +1 -1
- package/dist/loader.js +82 -51
- package/dist/loader.js.map +1 -1
- package/dist/noopHeuristic.d.ts +2 -2
- package/dist/noopHeuristic.d.ts.map +1 -1
- package/dist/noopHeuristic.js +6 -5
- package/dist/noopHeuristic.js.map +1 -1
- package/dist/packageVersion.d.ts +1 -1
- package/dist/packageVersion.js +1 -1
- package/dist/packageVersion.js.map +1 -1
- package/dist/protocol.d.ts +4 -2
- package/dist/protocol.d.ts.map +1 -1
- package/dist/protocol.js +25 -4
- package/dist/protocol.js.map +1 -1
- package/dist/quorum.d.ts +4 -1
- package/dist/quorum.d.ts.map +1 -1
- package/dist/quorum.js +1 -13
- package/dist/quorum.js.map +1 -1
- package/dist/retriableDocumentStorageService.d.ts.map +1 -1
- package/dist/retriableDocumentStorageService.js +4 -4
- package/dist/retriableDocumentStorageService.js.map +1 -1
- package/dist/utils.d.ts +8 -1
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +30 -11
- package/dist/utils.js.map +1 -1
- package/lib/audience.d.ts +1 -0
- package/lib/audience.d.ts.map +1 -1
- package/lib/audience.js +4 -2
- package/lib/audience.js.map +1 -1
- package/lib/catchUpMonitor.js +1 -1
- package/lib/catchUpMonitor.js.map +1 -1
- package/lib/connectionManager.d.ts +5 -5
- package/lib/connectionManager.d.ts.map +1 -1
- package/lib/connectionManager.js +74 -67
- package/lib/connectionManager.js.map +1 -1
- package/lib/connectionStateHandler.d.ts +15 -14
- package/lib/connectionStateHandler.d.ts.map +1 -1
- package/lib/connectionStateHandler.js +27 -29
- package/lib/connectionStateHandler.js.map +1 -1
- package/lib/container.d.ts +20 -9
- package/lib/container.d.ts.map +1 -1
- package/lib/container.js +288 -238
- package/lib/container.js.map +1 -1
- package/lib/containerContext.d.ts +2 -7
- package/lib/containerContext.d.ts.map +1 -1
- package/lib/containerContext.js +2 -14
- package/lib/containerContext.js.map +1 -1
- package/lib/containerStorageAdapter.d.ts.map +1 -1
- package/lib/containerStorageAdapter.js +5 -6
- package/lib/containerStorageAdapter.js.map +1 -1
- package/lib/contracts.d.ts +21 -8
- package/lib/contracts.d.ts.map +1 -1
- package/lib/contracts.js +3 -3
- package/lib/contracts.js.map +1 -1
- package/lib/debugLogger.d.ts +30 -0
- package/lib/debugLogger.d.ts.map +1 -0
- package/lib/debugLogger.js +91 -0
- package/lib/debugLogger.js.map +1 -0
- package/lib/deltaManager.d.ts +21 -10
- package/lib/deltaManager.d.ts.map +1 -1
- package/lib/deltaManager.js +88 -37
- package/lib/deltaManager.js.map +1 -1
- package/lib/deltaQueue.d.ts +1 -1
- package/lib/deltaQueue.d.ts.map +1 -1
- package/lib/deltaQueue.js +3 -3
- package/lib/deltaQueue.js.map +1 -1
- package/lib/disposal.d.ts +2 -2
- package/lib/disposal.d.ts.map +1 -1
- package/lib/disposal.js +1 -1
- package/lib/disposal.js.map +1 -1
- package/lib/error.d.ts +23 -0
- package/lib/error.d.ts.map +1 -0
- package/lib/error.js +28 -0
- package/lib/error.js.map +1 -0
- package/lib/loader.d.ts +22 -3
- package/lib/loader.d.ts.map +1 -1
- package/lib/loader.js +82 -51
- package/lib/loader.js.map +1 -1
- package/lib/noopHeuristic.d.ts +2 -2
- package/lib/noopHeuristic.d.ts.map +1 -1
- package/lib/noopHeuristic.js +2 -1
- package/lib/noopHeuristic.js.map +1 -1
- package/lib/packageVersion.d.ts +1 -1
- package/lib/packageVersion.js +1 -1
- package/lib/packageVersion.js.map +1 -1
- package/lib/protocol.d.ts +4 -2
- package/lib/protocol.d.ts.map +1 -1
- package/lib/protocol.js +25 -4
- package/lib/protocol.js.map +1 -1
- package/lib/quorum.d.ts +4 -1
- package/lib/quorum.d.ts.map +1 -1
- package/lib/quorum.js +0 -11
- package/lib/quorum.js.map +1 -1
- package/lib/retriableDocumentStorageService.d.ts.map +1 -1
- package/lib/retriableDocumentStorageService.js +2 -2
- package/lib/retriableDocumentStorageService.js.map +1 -1
- package/lib/utils.d.ts +8 -1
- package/lib/utils.d.ts.map +1 -1
- package/lib/utils.js +25 -7
- package/lib/utils.js.map +1 -1
- package/package.json +26 -32
- package/src/audience.ts +7 -1
- package/src/catchUpMonitor.ts +1 -1
- package/src/connectionManager.ts +75 -51
- package/src/connectionStateHandler.ts +31 -38
- package/src/container.ts +335 -240
- package/src/containerContext.ts +0 -16
- package/src/containerStorageAdapter.ts +2 -1
- package/src/contracts.ts +27 -11
- package/src/debugLogger.ts +113 -0
- package/src/deltaManager.ts +84 -34
- package/src/deltaQueue.ts +2 -1
- package/src/disposal.ts +2 -2
- package/src/error.ts +44 -0
- package/src/loader.ts +83 -35
- package/src/noopHeuristic.ts +3 -2
- package/src/packageVersion.ts +1 -1
- package/src/protocol.ts +33 -2
- package/src/quorum.ts +0 -10
- package/src/retriableDocumentStorageService.ts +2 -4
- package/src/utils.ts +33 -8
|
@@ -3,14 +3,10 @@
|
|
|
3
3
|
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
4
4
|
* Licensed under the MIT License.
|
|
5
5
|
*/
|
|
6
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
7
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
8
|
-
};
|
|
9
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
7
|
exports.ConnectionManager = void 0;
|
|
11
|
-
const
|
|
12
|
-
const
|
|
13
|
-
const container_utils_1 = require("@fluidframework/container-utils");
|
|
8
|
+
const core_utils_1 = require("@fluidframework/core-utils");
|
|
9
|
+
const client_utils_1 = require("@fluid-internal/client-utils");
|
|
14
10
|
const driver_utils_1 = require("@fluidframework/driver-utils");
|
|
15
11
|
const protocol_definitions_1 = require("@fluidframework/protocol-definitions");
|
|
16
12
|
const telemetry_utils_1 = require("@fluidframework/telemetry-utils");
|
|
@@ -18,7 +14,6 @@ const contracts_1 = require("./contracts");
|
|
|
18
14
|
const deltaQueue_1 = require("./deltaQueue");
|
|
19
15
|
const protocol_1 = require("./protocol");
|
|
20
16
|
const utils_1 = require("./utils");
|
|
21
|
-
const MaxReconnectDelayInMs = 8000;
|
|
22
17
|
const InitialReconnectDelayInMs = 1000;
|
|
23
18
|
const DefaultChunkSize = 16 * 1024;
|
|
24
19
|
const fatalConnectErrorProp = { fatalConnectError: true };
|
|
@@ -40,7 +35,7 @@ const clientNoDeltaStream = {
|
|
|
40
35
|
scopes: [],
|
|
41
36
|
};
|
|
42
37
|
const clientIdNoDeltaStream = "storage-only client";
|
|
43
|
-
class NoDeltaStream extends
|
|
38
|
+
class NoDeltaStream extends client_utils_1.TypedEventEmitter {
|
|
44
39
|
constructor(storageOnlyReason) {
|
|
45
40
|
super();
|
|
46
41
|
this.storageOnlyReason = storageOnlyReason;
|
|
@@ -89,9 +84,8 @@ function isNoDeltaStreamConnection(connection) {
|
|
|
89
84
|
return connection instanceof NoDeltaStream;
|
|
90
85
|
}
|
|
91
86
|
const waitForOnline = async () => {
|
|
92
|
-
var _a;
|
|
93
87
|
// Only wait if we have a strong signal that we're offline - otherwise assume we're online.
|
|
94
|
-
if (
|
|
88
|
+
if (globalThis.navigator?.onLine === false && globalThis.addEventListener !== undefined) {
|
|
95
89
|
return new Promise((resolve) => {
|
|
96
90
|
const resolveAndRemoveListener = () => {
|
|
97
91
|
resolve();
|
|
@@ -175,15 +169,13 @@ class ConnectionManager {
|
|
|
175
169
|
* The current connection mode, initially read.
|
|
176
170
|
*/
|
|
177
171
|
get connectionMode() {
|
|
178
|
-
|
|
179
|
-
return (_b = (_a = this.connection) === null || _a === void 0 ? void 0 : _a.mode) !== null && _b !== void 0 ? _b : "read";
|
|
172
|
+
return this.connection?.mode ?? "read";
|
|
180
173
|
}
|
|
181
174
|
get connected() {
|
|
182
175
|
return this.connection !== undefined;
|
|
183
176
|
}
|
|
184
177
|
get clientId() {
|
|
185
|
-
|
|
186
|
-
return (_a = this.connection) === null || _a === void 0 ? void 0 : _a.clientId;
|
|
178
|
+
return this.connection?.clientId;
|
|
187
179
|
}
|
|
188
180
|
/**
|
|
189
181
|
* Automatic reconnecting enabled or disabled.
|
|
@@ -193,8 +185,7 @@ class ConnectionManager {
|
|
|
193
185
|
return this._reconnectMode;
|
|
194
186
|
}
|
|
195
187
|
get maxMessageSize() {
|
|
196
|
-
|
|
197
|
-
return (_c = (_b = (_a = this.connection) === null || _a === void 0 ? void 0 : _a.serviceConfiguration) === null || _b === void 0 ? void 0 : _b.maxMessageSize) !== null && _c !== void 0 ? _c : DefaultChunkSize;
|
|
188
|
+
return this.connection?.serviceConfiguration?.maxMessageSize ?? DefaultChunkSize;
|
|
198
189
|
}
|
|
199
190
|
get version() {
|
|
200
191
|
if (this.connection === undefined) {
|
|
@@ -203,12 +194,10 @@ class ConnectionManager {
|
|
|
203
194
|
return this.connection.version;
|
|
204
195
|
}
|
|
205
196
|
get serviceConfiguration() {
|
|
206
|
-
|
|
207
|
-
return (_a = this.connection) === null || _a === void 0 ? void 0 : _a.serviceConfiguration;
|
|
197
|
+
return this.connection?.serviceConfiguration;
|
|
208
198
|
}
|
|
209
199
|
get scopes() {
|
|
210
|
-
|
|
211
|
-
return (_a = this.connection) === null || _a === void 0 ? void 0 : _a.claims.scopes;
|
|
200
|
+
return this.connection?.claims.scopes;
|
|
212
201
|
}
|
|
213
202
|
get outbound() {
|
|
214
203
|
return this._outbound;
|
|
@@ -220,9 +209,11 @@ class ConnectionManager {
|
|
|
220
209
|
get connectionProps() {
|
|
221
210
|
return this.connection !== undefined
|
|
222
211
|
? this._connectionProps
|
|
223
|
-
:
|
|
212
|
+
: {
|
|
213
|
+
...this._connectionProps,
|
|
224
214
|
// Report how many ops this client sent in last disconnected session
|
|
225
|
-
sentOps: this.clientSequenceNumber
|
|
215
|
+
sentOps: this.clientSequenceNumber,
|
|
216
|
+
};
|
|
226
217
|
}
|
|
227
218
|
shouldJoinWrite() {
|
|
228
219
|
// We don't have to wait for ack for topmost NoOps. So subtract those.
|
|
@@ -292,26 +283,30 @@ class ConnectionManager {
|
|
|
292
283
|
// Ensure that things like triggerConnect() will short circuit
|
|
293
284
|
this._reconnectMode = contracts_1.ReconnectMode.Never;
|
|
294
285
|
this._outbound.clear();
|
|
295
|
-
const disconnectReason =
|
|
286
|
+
const disconnectReason = {
|
|
287
|
+
text: "Closing DeltaManager",
|
|
288
|
+
error,
|
|
289
|
+
};
|
|
290
|
+
const oldReadonlyValue = this.readonly;
|
|
296
291
|
// This raises "disconnect" event if we have active connection.
|
|
297
292
|
this.disconnectFromDeltaStream(disconnectReason);
|
|
298
293
|
if (switchToReadonly) {
|
|
299
294
|
// Notify everyone we are in read-only state.
|
|
300
295
|
// Useful for data stores in case we hit some critical error,
|
|
301
296
|
// to switch to a mode where user edits are not accepted
|
|
302
|
-
this.set_readonlyPermissions(true);
|
|
297
|
+
this.set_readonlyPermissions(true, oldReadonlyValue);
|
|
303
298
|
}
|
|
304
299
|
}
|
|
305
300
|
/**
|
|
306
301
|
* Enables or disables automatic reconnecting.
|
|
307
302
|
* Will throw an error if reconnectMode set to Never.
|
|
308
303
|
*/
|
|
309
|
-
setAutoReconnect(mode) {
|
|
310
|
-
(0,
|
|
304
|
+
setAutoReconnect(mode, reason) {
|
|
305
|
+
(0, core_utils_1.assert)(mode !== contracts_1.ReconnectMode.Never && this._reconnectMode !== contracts_1.ReconnectMode.Never, 0x278 /* "API is not supported for non-connecting or closed container" */);
|
|
311
306
|
this._reconnectMode = mode;
|
|
312
307
|
if (mode !== contracts_1.ReconnectMode.Enabled) {
|
|
313
308
|
// immediately disconnect - do not rely on service eventually dropping connection.
|
|
314
|
-
this.disconnectFromDeltaStream(
|
|
309
|
+
this.disconnectFromDeltaStream(reason);
|
|
315
310
|
}
|
|
316
311
|
}
|
|
317
312
|
/**
|
|
@@ -342,7 +337,7 @@ class ConnectionManager {
|
|
|
342
337
|
this._forceReadonly = readonly;
|
|
343
338
|
if (oldValue !== this.readonly) {
|
|
344
339
|
if (this._reconnectMode === contracts_1.ReconnectMode.Never) {
|
|
345
|
-
throw new
|
|
340
|
+
throw new telemetry_utils_1.UsageError("API is not supported for non-connecting or closed container");
|
|
346
341
|
}
|
|
347
342
|
let reconnect = false;
|
|
348
343
|
if (this.readonly === true) {
|
|
@@ -354,31 +349,29 @@ class ConnectionManager {
|
|
|
354
349
|
// host logic error.
|
|
355
350
|
this.logger.sendErrorEvent({ eventName: "ForceReadonlyPendingChanged" });
|
|
356
351
|
}
|
|
357
|
-
reconnect = this.disconnectFromDeltaStream("Force readonly");
|
|
352
|
+
reconnect = this.disconnectFromDeltaStream({ text: "Force readonly" });
|
|
358
353
|
}
|
|
359
354
|
this.props.readonlyChangeHandler(this.readonly);
|
|
360
355
|
if (reconnect) {
|
|
361
356
|
// reconnect if we disconnected from before.
|
|
362
|
-
this.triggerConnect("Force Readonly", "read");
|
|
357
|
+
this.triggerConnect({ text: "Force Readonly" }, "read");
|
|
363
358
|
}
|
|
364
359
|
}
|
|
365
360
|
}
|
|
366
|
-
set_readonlyPermissions(
|
|
367
|
-
|
|
368
|
-
this.
|
|
369
|
-
if (oldValue !== this.readonly) {
|
|
361
|
+
set_readonlyPermissions(newReadonlyValue, oldReadonlyValue) {
|
|
362
|
+
this._readonlyPermissions = newReadonlyValue;
|
|
363
|
+
if (oldReadonlyValue !== this.readonly) {
|
|
370
364
|
this.props.readonlyChangeHandler(this.readonly);
|
|
371
365
|
}
|
|
372
366
|
}
|
|
373
367
|
connect(reason, connectionMode) {
|
|
374
|
-
this.connectCore(reason, connectionMode).catch((
|
|
375
|
-
const normalizedError = (0, telemetry_utils_1.normalizeError)(
|
|
368
|
+
this.connectCore(reason, connectionMode).catch((e) => {
|
|
369
|
+
const normalizedError = (0, telemetry_utils_1.normalizeError)(e, { props: fatalConnectErrorProp });
|
|
376
370
|
this.props.closeHandler(normalizedError);
|
|
377
371
|
});
|
|
378
372
|
}
|
|
379
373
|
async connectCore(reason, connectionMode) {
|
|
380
|
-
|
|
381
|
-
(0, common_utils_1.assert)(!this._disposed, 0x26a /* "not closed" */);
|
|
374
|
+
(0, core_utils_1.assert)(!this._disposed, 0x26a /* "not closed" */);
|
|
382
375
|
if (this.connection !== undefined) {
|
|
383
376
|
return; // Connection attempt already completed successfully
|
|
384
377
|
}
|
|
@@ -386,10 +379,10 @@ class ConnectionManager {
|
|
|
386
379
|
if (this.pendingConnection !== undefined) {
|
|
387
380
|
pendingConnectionMode = this.pendingConnection.connectionMode;
|
|
388
381
|
this.cancelConnection(reason); // Throw out in-progress connection attempt in favor of new attempt
|
|
389
|
-
(0,
|
|
382
|
+
(0, core_utils_1.assert)(this.pendingConnection === undefined, 0x344 /* this.pendingConnection should be undefined */);
|
|
390
383
|
}
|
|
391
384
|
// If there is no specified ConnectionMode, try the previous mode, if there is no previous mode use default
|
|
392
|
-
let requestedMode =
|
|
385
|
+
let requestedMode = connectionMode ?? pendingConnectionMode ?? this.defaultReconnectionMode;
|
|
393
386
|
// if we have any non-acked ops from last connection, reconnect as "write".
|
|
394
387
|
// without that we would connect in view-only mode, which will result in immediate
|
|
395
388
|
// firing of "connected" event from Container and switch of current clientId (as tracked
|
|
@@ -399,19 +392,19 @@ class ConnectionManager {
|
|
|
399
392
|
requestedMode = "write";
|
|
400
393
|
}
|
|
401
394
|
const docService = this.serviceProvider();
|
|
402
|
-
(0,
|
|
395
|
+
(0, core_utils_1.assert)(docService !== undefined, 0x2a7 /* "Container is not attached" */);
|
|
403
396
|
let connection;
|
|
404
|
-
if (
|
|
397
|
+
if (docService.policies?.storageOnly === true) {
|
|
405
398
|
connection = new NoDeltaStream();
|
|
406
399
|
this.setupNewSuccessfulConnection(connection, "read", reason);
|
|
407
|
-
(0,
|
|
400
|
+
(0, core_utils_1.assert)(this.pendingConnection === undefined, 0x2b3 /* "logic error" */);
|
|
408
401
|
return;
|
|
409
402
|
}
|
|
410
403
|
let delayMs = InitialReconnectDelayInMs;
|
|
411
404
|
let connectRepeatCount = 0;
|
|
412
|
-
const connectStartTime =
|
|
405
|
+
const connectStartTime = client_utils_1.performance.now();
|
|
413
406
|
let lastError;
|
|
414
|
-
const abortController = new
|
|
407
|
+
const abortController = new AbortController();
|
|
415
408
|
const abortSignal = abortController.signal;
|
|
416
409
|
this.pendingConnection = {
|
|
417
410
|
abort: () => {
|
|
@@ -429,7 +422,7 @@ class ConnectionManager {
|
|
|
429
422
|
this.logger.sendTelemetryEvent({
|
|
430
423
|
eventName: "ConnectionAttemptCancelled",
|
|
431
424
|
attempts: connectRepeatCount,
|
|
432
|
-
duration: telemetry_utils_1.
|
|
425
|
+
duration: (0, telemetry_utils_1.formatTick)(client_utils_1.performance.now() - connectStartTime),
|
|
433
426
|
connectionEstablished: false,
|
|
434
427
|
});
|
|
435
428
|
return;
|
|
@@ -437,7 +430,10 @@ class ConnectionManager {
|
|
|
437
430
|
connectRepeatCount++;
|
|
438
431
|
try {
|
|
439
432
|
this.client.mode = requestedMode;
|
|
440
|
-
connection = await docService.connectToDeltaStream(
|
|
433
|
+
connection = await docService.connectToDeltaStream({
|
|
434
|
+
...this.client,
|
|
435
|
+
mode: requestedMode,
|
|
436
|
+
});
|
|
441
437
|
if (connection.disposed) {
|
|
442
438
|
// Nobody observed this connection, so drop it on the floor and retry.
|
|
443
439
|
this.logger.sendTelemetryEvent({ eventName: "ReceivedClosedConnection" });
|
|
@@ -461,10 +457,10 @@ class ConnectionManager {
|
|
|
461
457
|
attempts: connectRepeatCount,
|
|
462
458
|
delay: delayMs,
|
|
463
459
|
eventName: "DeltaConnectionFailureToConnect",
|
|
464
|
-
duration: telemetry_utils_1.
|
|
460
|
+
duration: (0, telemetry_utils_1.formatTick)(client_utils_1.performance.now() - connectStartTime),
|
|
465
461
|
}, origError);
|
|
466
462
|
lastError = origError;
|
|
467
|
-
const waitStartTime =
|
|
463
|
+
const waitStartTime = client_utils_1.performance.now();
|
|
468
464
|
const retryDelayFromError = (0, driver_utils_1.getRetryDelayFromError)(origError);
|
|
469
465
|
if (retryDelayFromError !== undefined) {
|
|
470
466
|
// If the error told us to wait, then we wait.
|
|
@@ -473,12 +469,12 @@ class ConnectionManager {
|
|
|
473
469
|
setTimeout(resolve, retryDelayFromError);
|
|
474
470
|
});
|
|
475
471
|
}
|
|
476
|
-
else if (
|
|
472
|
+
else if (globalThis.navigator?.onLine !== false) {
|
|
477
473
|
// If the error didn't tell us to wait, let's still wait a little bit before retrying.
|
|
478
474
|
// We skip this delay if we're confident we're offline, because we probably just need to wait to come back online.
|
|
479
475
|
await new Promise((resolve) => {
|
|
480
476
|
setTimeout(resolve, delayMs);
|
|
481
|
-
delayMs = Math.min(delayMs * 2,
|
|
477
|
+
delayMs = Math.min(delayMs * 2, (0, driver_utils_1.calculateMaxWaitTime)(origError));
|
|
482
478
|
});
|
|
483
479
|
}
|
|
484
480
|
// If we believe we're offline, we assume there's no point in trying until we at least think we're online.
|
|
@@ -487,7 +483,7 @@ class ConnectionManager {
|
|
|
487
483
|
await waitForOnline();
|
|
488
484
|
this.logger.sendPerformanceEvent({
|
|
489
485
|
eventName: "WaitBetweenConnectionAttempts",
|
|
490
|
-
duration:
|
|
486
|
+
duration: client_utils_1.performance.now() - waitStartTime,
|
|
491
487
|
details: JSON.stringify({
|
|
492
488
|
retryDelayFromError,
|
|
493
489
|
delayMs,
|
|
@@ -500,7 +496,7 @@ class ConnectionManager {
|
|
|
500
496
|
(0, driver_utils_1.logNetworkFailure)(this.logger, {
|
|
501
497
|
eventName: "MultipleDeltaConnectionFailures",
|
|
502
498
|
attempts: connectRepeatCount,
|
|
503
|
-
duration: telemetry_utils_1.
|
|
499
|
+
duration: (0, telemetry_utils_1.formatTick)(client_utils_1.performance.now() - connectStartTime),
|
|
504
500
|
}, lastError);
|
|
505
501
|
}
|
|
506
502
|
// Check for abort signal after while loop as well
|
|
@@ -509,7 +505,7 @@ class ConnectionManager {
|
|
|
509
505
|
this.logger.sendTelemetryEvent({
|
|
510
506
|
eventName: "ConnectionAttemptCancelled",
|
|
511
507
|
attempts: connectRepeatCount,
|
|
512
|
-
duration: telemetry_utils_1.
|
|
508
|
+
duration: (0, telemetry_utils_1.formatTick)(client_utils_1.performance.now() - connectStartTime),
|
|
513
509
|
connectionEstablished: true,
|
|
514
510
|
});
|
|
515
511
|
return;
|
|
@@ -539,7 +535,7 @@ class ConnectionManager {
|
|
|
539
535
|
* @param error - Error causing the disconnect if any.
|
|
540
536
|
* @returns A boolean that indicates if there was an existing connection (or pending connection) to disconnect
|
|
541
537
|
*/
|
|
542
|
-
disconnectFromDeltaStream(reason
|
|
538
|
+
disconnectFromDeltaStream(reason) {
|
|
543
539
|
this.pendingReconnect = false;
|
|
544
540
|
if (this.connection === undefined) {
|
|
545
541
|
if (this.pendingConnection !== undefined) {
|
|
@@ -548,7 +544,7 @@ class ConnectionManager {
|
|
|
548
544
|
}
|
|
549
545
|
return false;
|
|
550
546
|
}
|
|
551
|
-
(0,
|
|
547
|
+
(0, core_utils_1.assert)(this.pendingConnection === undefined, 0x27b /* "reentrancy may result in incorrect behavior" */);
|
|
552
548
|
const connection = this.connection;
|
|
553
549
|
// Avoid any re-entrancy - clear object reference
|
|
554
550
|
this.connection = undefined;
|
|
@@ -563,7 +559,7 @@ class ConnectionManager {
|
|
|
563
559
|
this._outbound.pause();
|
|
564
560
|
this._outbound.clear();
|
|
565
561
|
connection.dispose();
|
|
566
|
-
this.props.disconnectHandler(reason
|
|
562
|
+
this.props.disconnectHandler(reason);
|
|
567
563
|
this._connectionVerboseProps = {};
|
|
568
564
|
return true;
|
|
569
565
|
}
|
|
@@ -571,11 +567,14 @@ class ConnectionManager {
|
|
|
571
567
|
* Cancel in-progress connection attempt.
|
|
572
568
|
*/
|
|
573
569
|
cancelConnection(reason) {
|
|
574
|
-
(0,
|
|
570
|
+
(0, core_utils_1.assert)(this.pendingConnection !== undefined, 0x345 /* this.pendingConnection is undefined when trying to cancel */);
|
|
575
571
|
this.pendingConnection.abort();
|
|
576
572
|
this.pendingConnection = undefined;
|
|
577
573
|
this.logger.sendTelemetryEvent({ eventName: "ConnectionCancelReceived" });
|
|
578
|
-
this.props.cancelConnectionHandler(
|
|
574
|
+
this.props.cancelConnectionHandler({
|
|
575
|
+
text: `Cancel Pending Connection due to ${reason.text}`,
|
|
576
|
+
error: reason.error,
|
|
577
|
+
});
|
|
579
578
|
}
|
|
580
579
|
/**
|
|
581
580
|
* Once we've successfully gotten a connection, we need to set up state, attach event listeners, and process
|
|
@@ -583,11 +582,11 @@ class ConnectionManager {
|
|
|
583
582
|
* @param connection - The newly established connection
|
|
584
583
|
*/
|
|
585
584
|
setupNewSuccessfulConnection(connection, requestedMode, reason) {
|
|
586
|
-
var _a;
|
|
587
585
|
// Old connection should have been cleaned up before establishing a new one
|
|
588
|
-
(0,
|
|
589
|
-
(0,
|
|
586
|
+
(0, core_utils_1.assert)(this.connection === undefined, 0x0e6 /* "old connection exists on new connection setup" */);
|
|
587
|
+
(0, core_utils_1.assert)(!connection.disposed, 0x28a /* "can't be disposed - Callers need to ensure that!" */);
|
|
590
588
|
this.pendingConnection = undefined;
|
|
589
|
+
const oldReadonlyValue = this.readonly;
|
|
591
590
|
this.connection = connection;
|
|
592
591
|
// Does information in scopes & mode matches?
|
|
593
592
|
// If we asked for "write" and got "read", then file is read-only
|
|
@@ -602,12 +601,12 @@ class ConnectionManager {
|
|
|
602
601
|
}
|
|
603
602
|
// This connection mode validation logic is moving to the driver layer in 0.44. These two asserts can be
|
|
604
603
|
// removed after those packages have released and become ubiquitous.
|
|
605
|
-
(0,
|
|
606
|
-
(0,
|
|
607
|
-
this.set_readonlyPermissions(readonly);
|
|
604
|
+
(0, core_utils_1.assert)(requestedMode === "read" || readonly === (this.connectionMode === "read"), 0x0e7 /* "claims/connectionMode mismatch" */);
|
|
605
|
+
(0, core_utils_1.assert)(!readonly || this.connectionMode === "read", 0x0e8 /* "readonly perf with write connection" */);
|
|
606
|
+
this.set_readonlyPermissions(readonly, oldReadonlyValue);
|
|
608
607
|
if (this._disposed) {
|
|
609
608
|
// Raise proper events, Log telemetry event and close connection.
|
|
610
|
-
this.disconnectFromDeltaStream("ConnectionManager already closed");
|
|
609
|
+
this.disconnectFromDeltaStream({ text: "ConnectionManager already closed" });
|
|
611
610
|
return;
|
|
612
611
|
}
|
|
613
612
|
this._outbound.resume();
|
|
@@ -664,7 +663,7 @@ class ConnectionManager {
|
|
|
664
663
|
}),
|
|
665
664
|
};
|
|
666
665
|
this.props.signalHandler(clearSignal);
|
|
667
|
-
for (const priorClient of
|
|
666
|
+
for (const priorClient of connection.initialClients ?? []) {
|
|
668
667
|
const joinSignal = {
|
|
669
668
|
clientId: null,
|
|
670
669
|
content: JSON.stringify({
|
|
@@ -692,7 +691,7 @@ class ConnectionManager {
|
|
|
692
691
|
* @returns A promise that resolves when the connection is reestablished or we stop trying
|
|
693
692
|
*/
|
|
694
693
|
reconnectOnError(requestedMode, error) {
|
|
695
|
-
this.reconnect(requestedMode, error.message, error).catch(this.props.closeHandler);
|
|
694
|
+
this.reconnect(requestedMode, { text: error.message, error }).catch(this.props.closeHandler);
|
|
696
695
|
}
|
|
697
696
|
/**
|
|
698
697
|
* Disconnect the current connection and reconnect.
|
|
@@ -701,20 +700,20 @@ class ConnectionManager {
|
|
|
701
700
|
* @param error - Error reconnect information including whether or not to reconnect
|
|
702
701
|
* @returns A promise that resolves when the connection is reestablished or we stop trying
|
|
703
702
|
*/
|
|
704
|
-
async reconnect(requestedMode,
|
|
703
|
+
async reconnect(requestedMode, reason) {
|
|
705
704
|
// We quite often get protocol errors before / after observing nack/disconnect
|
|
706
705
|
// we do not want to run through same sequence twice.
|
|
707
706
|
// If we're already disconnected/disconnecting it's not appropriate to call this again.
|
|
708
|
-
(0,
|
|
709
|
-
this.disconnectFromDeltaStream(
|
|
707
|
+
(0, core_utils_1.assert)(this.connection !== undefined, 0x0eb /* "Missing connection for reconnect" */);
|
|
708
|
+
this.disconnectFromDeltaStream(reason);
|
|
710
709
|
// We will always trigger reconnect, even if canRetry is false.
|
|
711
710
|
// Any truly fatal error state will result in container close upon attempted reconnect,
|
|
712
711
|
// which is a preferable to closing abruptly when a live connection fails.
|
|
713
|
-
if (error
|
|
712
|
+
if (reason.error?.canRetry === false) {
|
|
714
713
|
this.logger.sendTelemetryEvent({
|
|
715
714
|
eventName: "reconnectingDespiteFatalError",
|
|
716
715
|
reconnectMode: this.reconnectMode,
|
|
717
|
-
}, error);
|
|
716
|
+
}, reason.error);
|
|
718
717
|
}
|
|
719
718
|
if (this.reconnectMode === contracts_1.ReconnectMode.Never) {
|
|
720
719
|
// Do not raise container error if we are closing just because we lost connection.
|
|
@@ -727,9 +726,9 @@ class ConnectionManager {
|
|
|
727
726
|
return;
|
|
728
727
|
}
|
|
729
728
|
// If the error tells us to wait before retrying, then do so.
|
|
730
|
-
const delayMs = (0, driver_utils_1.getRetryDelayFromError)(error);
|
|
731
|
-
if (error !== undefined && delayMs !== undefined) {
|
|
732
|
-
this.props.reconnectionDelayHandler(delayMs, error);
|
|
729
|
+
const delayMs = (0, driver_utils_1.getRetryDelayFromError)(reason.error);
|
|
730
|
+
if (reason.error !== undefined && delayMs !== undefined) {
|
|
731
|
+
this.props.reconnectionDelayHandler(delayMs, reason.error);
|
|
733
732
|
await new Promise((resolve) => {
|
|
734
733
|
setTimeout(resolve, delayMs);
|
|
735
734
|
});
|
|
@@ -738,15 +737,17 @@ class ConnectionManager {
|
|
|
738
737
|
// NOTE: This isn't strictly true for drivers that don't require network (e.g. local driver). Really this logic
|
|
739
738
|
// should probably live in the driver.
|
|
740
739
|
await waitForOnline();
|
|
741
|
-
this.triggerConnect(
|
|
742
|
-
|
|
743
|
-
|
|
740
|
+
this.triggerConnect({
|
|
741
|
+
text: reason.error !== undefined
|
|
742
|
+
? "Reconnecting due to Error"
|
|
743
|
+
: `Reconnecting due to: ${reason.text}`,
|
|
744
|
+
error: reason.error,
|
|
745
|
+
}, requestedMode);
|
|
744
746
|
}
|
|
745
747
|
prepareMessageToSend(message) {
|
|
746
|
-
var _a, _b;
|
|
747
748
|
if (this.readonly === true) {
|
|
748
|
-
(0,
|
|
749
|
-
const error = new
|
|
749
|
+
(0, core_utils_1.assert)(this.readOnlyInfo.readonly === true, 0x1f0 /* "Unexpected mismatch in readonly" */);
|
|
750
|
+
const error = new telemetry_utils_1.GenericError("deltaManagerReadonlySubmit", undefined /* error */, {
|
|
750
751
|
readonly: this.readOnlyInfo.readonly,
|
|
751
752
|
forcedReadonly: this.readOnlyInfo.forced,
|
|
752
753
|
readonlyPermissions: this.readOnlyInfo.permissions,
|
|
@@ -759,9 +760,9 @@ class ConnectionManager {
|
|
|
759
760
|
// reset clientSequenceNumber if we are using new clientId.
|
|
760
761
|
// we keep info about old connection as long as possible to be able to account for all non-acked ops
|
|
761
762
|
// that we pick up on next connection.
|
|
762
|
-
(0,
|
|
763
|
-
if (this.lastSubmittedClientId !==
|
|
764
|
-
this.lastSubmittedClientId =
|
|
763
|
+
(0, core_utils_1.assert)(!!this.connection, 0x0e4 /* "Lost old connection!" */);
|
|
764
|
+
if (this.lastSubmittedClientId !== this.connection?.clientId) {
|
|
765
|
+
this.lastSubmittedClientId = this.connection?.clientId;
|
|
765
766
|
this.clientSequenceNumber = 0;
|
|
766
767
|
this.clientSequenceNumberObserved = 0;
|
|
767
768
|
}
|
|
@@ -771,7 +772,10 @@ class ConnectionManager {
|
|
|
771
772
|
else {
|
|
772
773
|
this.localOpsToIgnore = 0;
|
|
773
774
|
}
|
|
774
|
-
return
|
|
775
|
+
return {
|
|
776
|
+
...message,
|
|
777
|
+
clientSequenceNumber: ++this.clientSequenceNumber,
|
|
778
|
+
};
|
|
775
779
|
}
|
|
776
780
|
submitSignal(content) {
|
|
777
781
|
if (this.connection !== undefined) {
|
|
@@ -782,7 +786,7 @@ class ConnectionManager {
|
|
|
782
786
|
}
|
|
783
787
|
}
|
|
784
788
|
sendMessages(messages) {
|
|
785
|
-
(0,
|
|
789
|
+
(0, core_utils_1.assert)(this.connected, 0x2b4 /* "not connected on sending ops!" */);
|
|
786
790
|
// If connection is "read" or implicit "read" (got leave op for "write" connection),
|
|
787
791
|
// then op can't make it through - we will get a nack if op is sent.
|
|
788
792
|
// We can short-circuit this process.
|
|
@@ -797,24 +801,24 @@ class ConnectionManager {
|
|
|
797
801
|
if (this.pendingReconnect) {
|
|
798
802
|
// still valid?
|
|
799
803
|
await this.reconnect("write", // connectionMode
|
|
800
|
-
"Switch to write");
|
|
804
|
+
{ text: "Switch to write" });
|
|
801
805
|
}
|
|
802
806
|
})
|
|
803
807
|
.catch(() => { });
|
|
804
808
|
}
|
|
805
809
|
return;
|
|
806
810
|
}
|
|
807
|
-
(0,
|
|
811
|
+
(0, core_utils_1.assert)(!this.pendingReconnect, 0x2b5 /* "logic error" */);
|
|
808
812
|
this._outbound.push(messages);
|
|
809
813
|
}
|
|
810
814
|
beforeProcessingIncomingOp(message) {
|
|
811
815
|
// if we have connection, and message is local, then we better treat is as local!
|
|
812
|
-
(0,
|
|
816
|
+
(0, core_utils_1.assert)(this.clientId !== message.clientId || this.lastSubmittedClientId === message.clientId, 0x0ee /* "Not accounting local messages correctly" */);
|
|
813
817
|
if (this.lastSubmittedClientId !== undefined &&
|
|
814
818
|
this.lastSubmittedClientId === message.clientId) {
|
|
815
819
|
const clientSequenceNumber = message.clientSequenceNumber;
|
|
816
|
-
(0,
|
|
817
|
-
(0,
|
|
820
|
+
(0, core_utils_1.assert)(this.clientSequenceNumberObserved < clientSequenceNumber, 0x0ef /* "client seq# not growing" */);
|
|
821
|
+
(0, core_utils_1.assert)(clientSequenceNumber <= this.clientSequenceNumber, 0x0f0 /* "Incoming local client seq# > generated by this client" */);
|
|
818
822
|
this.clientSequenceNumberObserved = clientSequenceNumber;
|
|
819
823
|
}
|
|
820
824
|
if (message.type === protocol_definitions_1.MessageType.ClientLeave) {
|
|
@@ -830,7 +834,7 @@ class ConnectionManager {
|
|
|
830
834
|
// Clients need to be able to transition to "read" state after some time of inactivity!
|
|
831
835
|
// Note - this may close container!
|
|
832
836
|
this.reconnect("read", // connectionMode
|
|
833
|
-
"Switch to read").catch((error) => {
|
|
837
|
+
{ text: "Switch to read" }).catch((error) => {
|
|
834
838
|
this.logger.sendErrorEvent({ eventName: "SwitchToReadConnection" }, error);
|
|
835
839
|
});
|
|
836
840
|
}
|