@fluidframework/container-loader 2.0.0-dev.2.3.0.115467 → 2.0.0-dev.4.1.0.148229
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/.eslintrc.js +18 -21
- package/.mocharc.js +2 -2
- package/README.md +65 -44
- package/api-extractor.json +2 -2
- package/closeAndGetPendingLocalState.md +51 -0
- package/dist/audience.d.ts +0 -1
- package/dist/audience.d.ts.map +1 -1
- package/dist/audience.js.map +1 -1
- package/dist/catchUpMonitor.d.ts.map +1 -1
- package/dist/catchUpMonitor.js.map +1 -1
- package/dist/collabWindowTracker.d.ts.map +1 -1
- package/dist/collabWindowTracker.js.map +1 -1
- package/dist/connectionManager.d.ts +5 -5
- package/dist/connectionManager.d.ts.map +1 -1
- package/dist/connectionManager.js +107 -44
- package/dist/connectionManager.js.map +1 -1
- package/dist/connectionState.d.ts.map +1 -1
- package/dist/connectionState.js.map +1 -1
- package/dist/connectionStateHandler.d.ts +7 -7
- package/dist/connectionStateHandler.d.ts.map +1 -1
- package/dist/connectionStateHandler.js +50 -21
- package/dist/connectionStateHandler.js.map +1 -1
- package/dist/container.d.ts +64 -5
- package/dist/container.d.ts.map +1 -1
- package/dist/container.js +329 -137
- package/dist/container.js.map +1 -1
- package/dist/containerContext.d.ts +19 -8
- package/dist/containerContext.d.ts.map +1 -1
- package/dist/containerContext.js +58 -14
- package/dist/containerContext.js.map +1 -1
- package/dist/containerStorageAdapter.d.ts +41 -2
- package/dist/containerStorageAdapter.d.ts.map +1 -1
- package/dist/containerStorageAdapter.js +88 -14
- package/dist/containerStorageAdapter.js.map +1 -1
- package/dist/contracts.d.ts +3 -3
- package/dist/contracts.d.ts.map +1 -1
- package/dist/contracts.js.map +1 -1
- package/dist/deltaManager.d.ts +21 -8
- package/dist/deltaManager.d.ts.map +1 -1
- package/dist/deltaManager.js +112 -37
- package/dist/deltaManager.js.map +1 -1
- package/dist/deltaManagerProxy.d.ts +10 -22
- package/dist/deltaManagerProxy.d.ts.map +1 -1
- package/dist/deltaManagerProxy.js +14 -50
- package/dist/deltaManagerProxy.js.map +1 -1
- package/dist/deltaQueue.d.ts.map +1 -1
- package/dist/deltaQueue.js +4 -2
- package/dist/deltaQueue.js.map +1 -1
- package/dist/index.d.ts +4 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -3
- package/dist/index.js.map +1 -1
- package/dist/loader.d.ts +13 -4
- package/dist/loader.d.ts.map +1 -1
- package/dist/loader.js +38 -24
- package/dist/loader.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.map +1 -1
- package/dist/protocol.js +2 -1
- package/dist/protocol.js.map +1 -1
- package/dist/protocolTreeDocumentStorageService.d.ts +6 -2
- package/dist/protocolTreeDocumentStorageService.d.ts.map +1 -1
- package/dist/protocolTreeDocumentStorageService.js +7 -4
- package/dist/protocolTreeDocumentStorageService.js.map +1 -1
- package/dist/quorum.d.ts.map +1 -1
- package/dist/quorum.js.map +1 -1
- package/dist/retriableDocumentStorageService.d.ts.map +1 -1
- package/dist/retriableDocumentStorageService.js +6 -2
- package/dist/retriableDocumentStorageService.js.map +1 -1
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +8 -5
- package/dist/utils.js.map +1 -1
- package/lib/audience.d.ts +0 -1
- package/lib/audience.d.ts.map +1 -1
- package/lib/audience.js.map +1 -1
- package/lib/catchUpMonitor.d.ts.map +1 -1
- package/lib/catchUpMonitor.js.map +1 -1
- package/lib/collabWindowTracker.d.ts.map +1 -1
- package/lib/collabWindowTracker.js.map +1 -1
- package/lib/connectionManager.d.ts +5 -5
- package/lib/connectionManager.d.ts.map +1 -1
- package/lib/connectionManager.js +110 -47
- package/lib/connectionManager.js.map +1 -1
- package/lib/connectionState.d.ts.map +1 -1
- package/lib/connectionState.js.map +1 -1
- package/lib/connectionStateHandler.d.ts +7 -7
- package/lib/connectionStateHandler.d.ts.map +1 -1
- package/lib/connectionStateHandler.js +50 -21
- package/lib/connectionStateHandler.js.map +1 -1
- package/lib/container.d.ts +64 -5
- package/lib/container.d.ts.map +1 -1
- package/lib/container.js +336 -144
- package/lib/container.js.map +1 -1
- package/lib/containerContext.d.ts +19 -8
- package/lib/containerContext.d.ts.map +1 -1
- package/lib/containerContext.js +59 -15
- package/lib/containerContext.js.map +1 -1
- package/lib/containerStorageAdapter.d.ts +41 -2
- package/lib/containerStorageAdapter.d.ts.map +1 -1
- package/lib/containerStorageAdapter.js +86 -14
- package/lib/containerStorageAdapter.js.map +1 -1
- package/lib/contracts.d.ts +3 -3
- package/lib/contracts.d.ts.map +1 -1
- package/lib/contracts.js.map +1 -1
- package/lib/deltaManager.d.ts +21 -8
- package/lib/deltaManager.d.ts.map +1 -1
- package/lib/deltaManager.js +114 -39
- package/lib/deltaManager.js.map +1 -1
- package/lib/deltaManagerProxy.d.ts +10 -22
- package/lib/deltaManagerProxy.d.ts.map +1 -1
- package/lib/deltaManagerProxy.js +14 -50
- package/lib/deltaManagerProxy.js.map +1 -1
- package/lib/deltaQueue.d.ts.map +1 -1
- package/lib/deltaQueue.js +4 -2
- package/lib/deltaQueue.js.map +1 -1
- package/lib/index.d.ts +4 -3
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +2 -2
- package/lib/index.js.map +1 -1
- package/lib/loader.d.ts +13 -4
- package/lib/loader.d.ts.map +1 -1
- package/lib/loader.js +37 -24
- package/lib/loader.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.map +1 -1
- package/lib/protocol.js +2 -1
- package/lib/protocol.js.map +1 -1
- package/lib/protocolTreeDocumentStorageService.d.ts +6 -2
- package/lib/protocolTreeDocumentStorageService.d.ts.map +1 -1
- package/lib/protocolTreeDocumentStorageService.js +7 -4
- package/lib/protocolTreeDocumentStorageService.js.map +1 -1
- package/lib/quorum.d.ts.map +1 -1
- package/lib/quorum.js.map +1 -1
- package/lib/retriableDocumentStorageService.d.ts.map +1 -1
- package/lib/retriableDocumentStorageService.js +6 -2
- package/lib/retriableDocumentStorageService.js.map +1 -1
- package/lib/utils.d.ts.map +1 -1
- package/lib/utils.js +8 -5
- package/lib/utils.js.map +1 -1
- package/package.json +67 -56
- package/prettier.config.cjs +1 -1
- package/src/audience.ts +51 -46
- package/src/catchUpMonitor.ts +39 -37
- package/src/collabWindowTracker.ts +75 -70
- package/src/connectionManager.ts +1040 -941
- package/src/connectionState.ts +19 -19
- package/src/connectionStateHandler.ts +557 -463
- package/src/container.ts +2147 -1784
- package/src/containerContext.ts +417 -345
- package/src/containerStorageAdapter.ts +268 -154
- package/src/contracts.ts +155 -153
- package/src/deltaManager.ts +1074 -945
- package/src/deltaManagerProxy.ts +88 -137
- package/src/deltaQueue.ts +155 -151
- package/src/index.ts +13 -17
- package/src/loader.ts +434 -427
- package/src/packageVersion.ts +1 -1
- package/src/protocol.ts +93 -87
- package/src/protocolTreeDocumentStorageService.ts +34 -34
- package/src/quorum.ts +34 -34
- package/src/retriableDocumentStorageService.ts +118 -102
- package/src/utils.ts +93 -83
- package/tsconfig.esnext.json +6 -6
- package/tsconfig.json +8 -12
|
@@ -11,6 +11,7 @@ exports.ConnectionManager = void 0;
|
|
|
11
11
|
const abort_controller_1 = __importDefault(require("abort-controller"));
|
|
12
12
|
const common_utils_1 = require("@fluidframework/common-utils");
|
|
13
13
|
const container_utils_1 = require("@fluidframework/container-utils");
|
|
14
|
+
const driver_definitions_1 = require("@fluidframework/driver-definitions");
|
|
14
15
|
const driver_utils_1 = require("@fluidframework/driver-utils");
|
|
15
16
|
const protocol_definitions_1 = require("@fluidframework/protocol-definitions");
|
|
16
17
|
const telemetry_utils_1 = require("@fluidframework/telemetry-utils");
|
|
@@ -52,7 +53,9 @@ class NoDeltaStream extends common_utils_1.TypedEventEmitter {
|
|
|
52
53
|
this.version = "";
|
|
53
54
|
this.initialMessages = [];
|
|
54
55
|
this.initialSignals = [];
|
|
55
|
-
this.initialClients = [
|
|
56
|
+
this.initialClients = [
|
|
57
|
+
{ client: clientNoDeltaStream, clientId: clientIdNoDeltaStream },
|
|
58
|
+
];
|
|
56
59
|
this.serviceConfiguration = {
|
|
57
60
|
maxMessageSize: 0,
|
|
58
61
|
blockSize: 0,
|
|
@@ -74,9 +77,26 @@ class NoDeltaStream extends common_utils_1.TypedEventEmitter {
|
|
|
74
77
|
content: { message: "Cannot submit signal with storage-only connection", code: 403 },
|
|
75
78
|
});
|
|
76
79
|
}
|
|
77
|
-
get disposed() {
|
|
78
|
-
|
|
80
|
+
get disposed() {
|
|
81
|
+
return this._disposed;
|
|
82
|
+
}
|
|
83
|
+
dispose() {
|
|
84
|
+
this._disposed = true;
|
|
85
|
+
}
|
|
79
86
|
}
|
|
87
|
+
const waitForOnline = async () => {
|
|
88
|
+
var _a;
|
|
89
|
+
// Only wait if we have a strong signal that we're offline - otherwise assume we're online.
|
|
90
|
+
if (((_a = globalThis.navigator) === null || _a === void 0 ? void 0 : _a.onLine) === false && globalThis.addEventListener !== undefined) {
|
|
91
|
+
return new Promise((resolve) => {
|
|
92
|
+
const resolveAndRemoveListener = () => {
|
|
93
|
+
resolve();
|
|
94
|
+
globalThis.removeEventListener("online", resolveAndRemoveListener);
|
|
95
|
+
};
|
|
96
|
+
globalThis.addEventListener("online", resolveAndRemoveListener);
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
};
|
|
80
100
|
/**
|
|
81
101
|
* Implementation of IConnectionManager, used by Container class
|
|
82
102
|
* Implements constant connectivity to relay service, by reconnecting in case of lost connection or error.
|
|
@@ -94,12 +114,12 @@ class ConnectionManager {
|
|
|
94
114
|
this.pendingReconnect = false;
|
|
95
115
|
this.clientSequenceNumber = 0;
|
|
96
116
|
this.clientSequenceNumberObserved = 0;
|
|
97
|
-
/** Counts the number of
|
|
117
|
+
/** Counts the number of non-runtime ops sent by the client which may not be acked. */
|
|
98
118
|
this.localOpsToIgnore = 0;
|
|
99
119
|
this.connectFirstConnection = true;
|
|
100
120
|
this._connectionVerboseProps = {};
|
|
101
121
|
this._connectionProps = {};
|
|
102
|
-
this.
|
|
122
|
+
this._disposed = false;
|
|
103
123
|
this.opHandler = (documentId, messagesArg) => {
|
|
104
124
|
const messages = Array.isArray(messagesArg) ? messagesArg : [messagesArg];
|
|
105
125
|
this.props.incomingOpHandler(messages, "opHandler");
|
|
@@ -143,7 +163,9 @@ class ConnectionManager {
|
|
|
143
163
|
this.props.closeHandler((0, telemetry_utils_1.normalizeError)(error));
|
|
144
164
|
});
|
|
145
165
|
}
|
|
146
|
-
get connectionVerboseProps() {
|
|
166
|
+
get connectionVerboseProps() {
|
|
167
|
+
return this._connectionVerboseProps;
|
|
168
|
+
}
|
|
147
169
|
/**
|
|
148
170
|
* The current connection mode, initially read.
|
|
149
171
|
*/
|
|
@@ -151,8 +173,13 @@ class ConnectionManager {
|
|
|
151
173
|
var _a, _b;
|
|
152
174
|
return (_b = (_a = this.connection) === null || _a === void 0 ? void 0 : _a.mode) !== null && _b !== void 0 ? _b : "read";
|
|
153
175
|
}
|
|
154
|
-
get connected() {
|
|
155
|
-
|
|
176
|
+
get connected() {
|
|
177
|
+
return this.connection !== undefined;
|
|
178
|
+
}
|
|
179
|
+
get clientId() {
|
|
180
|
+
var _a;
|
|
181
|
+
return (_a = this.connection) === null || _a === void 0 ? void 0 : _a.clientId;
|
|
182
|
+
}
|
|
156
183
|
/**
|
|
157
184
|
* Automatic reconnecting enabled or disabled.
|
|
158
185
|
* If set to Never, then reconnecting will never be allowed.
|
|
@@ -184,7 +211,7 @@ class ConnectionManager {
|
|
|
184
211
|
/**
|
|
185
212
|
* Returns set of props that can be logged in telemetry that provide some insights / statistics
|
|
186
213
|
* about current or last connection (if there is no connection at the moment)
|
|
187
|
-
|
|
214
|
+
*/
|
|
188
215
|
get connectionProps() {
|
|
189
216
|
return this.connection !== undefined
|
|
190
217
|
? this._connectionProps
|
|
@@ -194,7 +221,7 @@ class ConnectionManager {
|
|
|
194
221
|
}
|
|
195
222
|
shouldJoinWrite() {
|
|
196
223
|
// We don't have to wait for ack for topmost NoOps. So subtract those.
|
|
197
|
-
return this.clientSequenceNumberObserved <
|
|
224
|
+
return (this.clientSequenceNumberObserved < this.clientSequenceNumber - this.localOpsToIgnore);
|
|
198
225
|
}
|
|
199
226
|
/**
|
|
200
227
|
* Tells if container is in read-only mode.
|
|
@@ -227,37 +254,38 @@ class ConnectionManager {
|
|
|
227
254
|
return {
|
|
228
255
|
claims: connection.claims,
|
|
229
256
|
clientId: connection.clientId,
|
|
230
|
-
existing: connection.existing,
|
|
231
257
|
checkpointSequenceNumber: connection.checkpointSequenceNumber,
|
|
232
|
-
get initialClients() {
|
|
258
|
+
get initialClients() {
|
|
259
|
+
return connection.initialClients;
|
|
260
|
+
},
|
|
233
261
|
mode: connection.mode,
|
|
234
262
|
serviceConfiguration: connection.serviceConfiguration,
|
|
235
263
|
version: connection.version,
|
|
236
264
|
};
|
|
237
265
|
}
|
|
238
|
-
dispose(error) {
|
|
239
|
-
if (this.
|
|
266
|
+
dispose(error, switchToReadonly = true) {
|
|
267
|
+
if (this._disposed) {
|
|
240
268
|
return;
|
|
241
269
|
}
|
|
242
|
-
this.
|
|
270
|
+
this._disposed = true;
|
|
243
271
|
this.pendingConnection = undefined;
|
|
244
272
|
// Ensure that things like triggerConnect() will short circuit
|
|
245
273
|
this._reconnectMode = contracts_1.ReconnectMode.Never;
|
|
246
274
|
this._outbound.clear();
|
|
247
|
-
const disconnectReason =
|
|
248
|
-
? `Closing DeltaManager (${error.message})`
|
|
249
|
-
: "Closing DeltaManager";
|
|
275
|
+
const disconnectReason = "Closing DeltaManager";
|
|
250
276
|
// This raises "disconnect" event if we have active connection.
|
|
251
277
|
this.disconnectFromDeltaStream(disconnectReason);
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
278
|
+
if (switchToReadonly) {
|
|
279
|
+
// Notify everyone we are in read-only state.
|
|
280
|
+
// Useful for data stores in case we hit some critical error,
|
|
281
|
+
// to switch to a mode where user edits are not accepted
|
|
282
|
+
this.set_readonlyPermissions(true);
|
|
283
|
+
}
|
|
256
284
|
}
|
|
257
285
|
/**
|
|
258
286
|
* Enables or disables automatic reconnecting.
|
|
259
287
|
* Will throw an error if reconnectMode set to Never.
|
|
260
|
-
|
|
288
|
+
*/
|
|
261
289
|
setAutoReconnect(mode) {
|
|
262
290
|
(0, common_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" */);
|
|
263
291
|
this._reconnectMode = mode;
|
|
@@ -329,8 +357,8 @@ class ConnectionManager {
|
|
|
329
357
|
});
|
|
330
358
|
}
|
|
331
359
|
async connectCore(connectionMode) {
|
|
332
|
-
var _a, _b;
|
|
333
|
-
(0, common_utils_1.assert)(!this.
|
|
360
|
+
var _a, _b, _c;
|
|
361
|
+
(0, common_utils_1.assert)(!this._disposed, 0x26a /* "not closed" */);
|
|
334
362
|
if (this.connection !== undefined) {
|
|
335
363
|
return; // Connection attempt already completed successfully
|
|
336
364
|
}
|
|
@@ -365,10 +393,15 @@ class ConnectionManager {
|
|
|
365
393
|
let lastError;
|
|
366
394
|
const abortController = new abort_controller_1.default();
|
|
367
395
|
const abortSignal = abortController.signal;
|
|
368
|
-
this.pendingConnection = {
|
|
396
|
+
this.pendingConnection = {
|
|
397
|
+
abort: () => {
|
|
398
|
+
abortController.abort();
|
|
399
|
+
},
|
|
400
|
+
connectionMode: requestedMode,
|
|
401
|
+
};
|
|
369
402
|
// This loop will keep trying to connect until successful, with a delay between each iteration.
|
|
370
403
|
while (connection === undefined) {
|
|
371
|
-
if (this.
|
|
404
|
+
if (this._disposed) {
|
|
372
405
|
throw new Error("Attempting to connect a closed DeltaManager");
|
|
373
406
|
}
|
|
374
407
|
if (abortSignal.aborted === true) {
|
|
@@ -391,8 +424,9 @@ class ConnectionManager {
|
|
|
391
424
|
}
|
|
392
425
|
}
|
|
393
426
|
catch (origError) {
|
|
394
|
-
if (typeof origError === "object" &&
|
|
395
|
-
|
|
427
|
+
if (typeof origError === "object" &&
|
|
428
|
+
origError !== null &&
|
|
429
|
+
(origError === null || origError === void 0 ? void 0 : origError.errorType) === driver_definitions_1.DriverErrorType.deltaStreamConnectionForbidden) {
|
|
396
430
|
connection = new NoDeltaStream();
|
|
397
431
|
requestedMode = "read";
|
|
398
432
|
break;
|
|
@@ -412,11 +446,25 @@ class ConnectionManager {
|
|
|
412
446
|
}, origError);
|
|
413
447
|
lastError = origError;
|
|
414
448
|
const retryDelayFromError = (0, driver_utils_1.getRetryDelayFromError)(origError);
|
|
415
|
-
delayMs = retryDelayFromError !== null && retryDelayFromError !== void 0 ? retryDelayFromError : Math.min(delayMs * 2, MaxReconnectDelayInMs);
|
|
416
449
|
if (retryDelayFromError !== undefined) {
|
|
450
|
+
// If the error told us to wait, then we wait.
|
|
417
451
|
this.props.reconnectionDelayHandler(retryDelayFromError, origError);
|
|
452
|
+
await new Promise((resolve) => {
|
|
453
|
+
setTimeout(resolve, retryDelayFromError);
|
|
454
|
+
});
|
|
455
|
+
}
|
|
456
|
+
else if (((_c = globalThis.navigator) === null || _c === void 0 ? void 0 : _c.onLine) !== false) {
|
|
457
|
+
// If the error didn't tell us to wait, let's still wait a little bit before retrying.
|
|
458
|
+
// We skip this delay if we're confident we're offline, because we probably just need to wait to come back online.
|
|
459
|
+
await new Promise((resolve) => {
|
|
460
|
+
setTimeout(resolve, delayMs);
|
|
461
|
+
delayMs = Math.min(delayMs * 2, MaxReconnectDelayInMs);
|
|
462
|
+
});
|
|
418
463
|
}
|
|
419
|
-
|
|
464
|
+
// If we believe we're offline, we assume there's no point in trying until we at least think we're online.
|
|
465
|
+
// NOTE: This isn't strictly true for drivers that don't require network (e.g. local driver). Really this logic
|
|
466
|
+
// should probably live in the driver.
|
|
467
|
+
await waitForOnline();
|
|
420
468
|
}
|
|
421
469
|
}
|
|
422
470
|
// If we retried more than once, log an event about how long it took (this will not log to error table)
|
|
@@ -446,7 +494,7 @@ class ConnectionManager {
|
|
|
446
494
|
* @param args - The connection arguments
|
|
447
495
|
*/
|
|
448
496
|
triggerConnect(connectionMode) {
|
|
449
|
-
// reconnect()
|
|
497
|
+
// reconnect() includes async awaits, and that causes potential race conditions
|
|
450
498
|
// where we might already have a connection. If it were to happen, it's possible that we will connect
|
|
451
499
|
// with different mode to `connectionMode`. Glancing through the caller chains, it looks like code should be
|
|
452
500
|
// fine (if needed, reconnect flow will get triggered again). Places where new mode matters should encode it
|
|
@@ -485,8 +533,8 @@ class ConnectionManager {
|
|
|
485
533
|
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
|
486
534
|
this._outbound.pause();
|
|
487
535
|
this._outbound.clear();
|
|
488
|
-
this.props.disconnectHandler(reason);
|
|
489
536
|
connection.dispose();
|
|
537
|
+
this.props.disconnectHandler(reason);
|
|
490
538
|
this._connectionVerboseProps = {};
|
|
491
539
|
return true;
|
|
492
540
|
}
|
|
@@ -516,14 +564,18 @@ class ConnectionManager {
|
|
|
516
564
|
// But if we ask read, server can still give us write.
|
|
517
565
|
const readonly = !connection.claims.scopes.includes(protocol_definitions_1.ScopeType.DocWrite);
|
|
518
566
|
if (connection.mode !== requestedMode) {
|
|
519
|
-
this.logger.sendTelemetryEvent({
|
|
567
|
+
this.logger.sendTelemetryEvent({
|
|
568
|
+
eventName: "ConnectionModeMismatch",
|
|
569
|
+
requestedMode,
|
|
570
|
+
mode: connection.mode,
|
|
571
|
+
});
|
|
520
572
|
}
|
|
521
573
|
// This connection mode validation logic is moving to the driver layer in 0.44. These two asserts can be
|
|
522
574
|
// removed after those packages have released and become ubiquitous.
|
|
523
575
|
(0, common_utils_1.assert)(requestedMode === "read" || readonly === (this.connectionMode === "read"), 0x0e7 /* "claims/connectionMode mismatch" */);
|
|
524
576
|
(0, common_utils_1.assert)(!readonly || this.connectionMode === "read", 0x0e8 /* "readonly perf with write connection" */);
|
|
525
577
|
this.set_readonlyPermissions(readonly);
|
|
526
|
-
if (this.
|
|
578
|
+
if (this._disposed) {
|
|
527
579
|
// Raise proper events, Log telemetry event and close connection.
|
|
528
580
|
this.disconnectFromDeltaStream("ConnectionManager already closed");
|
|
529
581
|
return;
|
|
@@ -556,7 +608,8 @@ class ConnectionManager {
|
|
|
556
608
|
this._connectionProps.connectionMode = connection.mode;
|
|
557
609
|
let last = -1;
|
|
558
610
|
if (initialMessages.length !== 0) {
|
|
559
|
-
this._connectionVerboseProps.connectionInitialOpsFrom =
|
|
611
|
+
this._connectionVerboseProps.connectionInitialOpsFrom =
|
|
612
|
+
initialMessages[0].sequenceNumber;
|
|
560
613
|
last = initialMessages[initialMessages.length - 1].sequenceNumber;
|
|
561
614
|
this._connectionVerboseProps.connectionInitialOpsTo = last + 1;
|
|
562
615
|
// Update knowledge of how far we are behind, before raising "connect" event
|
|
@@ -609,8 +662,7 @@ class ConnectionManager {
|
|
|
609
662
|
* @returns A promise that resolves when the connection is reestablished or we stop trying
|
|
610
663
|
*/
|
|
611
664
|
reconnectOnError(requestedMode, error) {
|
|
612
|
-
this.reconnect(requestedMode, error.message, error)
|
|
613
|
-
.catch(this.props.closeHandler);
|
|
665
|
+
this.reconnect(requestedMode, error.message, error).catch(this.props.closeHandler);
|
|
614
666
|
}
|
|
615
667
|
/**
|
|
616
668
|
* Disconnect the current connection and reconnect.
|
|
@@ -641,14 +693,21 @@ class ConnectionManager {
|
|
|
641
693
|
this.props.closeHandler();
|
|
642
694
|
}
|
|
643
695
|
// If closed then we can't reconnect
|
|
644
|
-
if (this.
|
|
696
|
+
if (this._disposed || this.reconnectMode !== contracts_1.ReconnectMode.Enabled) {
|
|
645
697
|
return;
|
|
646
698
|
}
|
|
699
|
+
// If the error tells us to wait before retrying, then do so.
|
|
647
700
|
const delayMs = (0, driver_utils_1.getRetryDelayFromError)(error);
|
|
648
701
|
if (error !== undefined && delayMs !== undefined) {
|
|
649
702
|
this.props.reconnectionDelayHandler(delayMs, error);
|
|
650
|
-
await
|
|
703
|
+
await new Promise((resolve) => {
|
|
704
|
+
setTimeout(resolve, delayMs);
|
|
705
|
+
});
|
|
651
706
|
}
|
|
707
|
+
// If we believe we're offline, we assume there's no point in trying again until we at least think we're online.
|
|
708
|
+
// NOTE: This isn't strictly true for drivers that don't require network (e.g. local driver). Really this logic
|
|
709
|
+
// should probably live in the driver.
|
|
710
|
+
await waitForOnline();
|
|
652
711
|
this.triggerConnect(requestedMode);
|
|
653
712
|
}
|
|
654
713
|
prepareMessageToSend(message) {
|
|
@@ -700,12 +759,15 @@ class ConnectionManager {
|
|
|
700
759
|
if (this.connectionMode === "read") {
|
|
701
760
|
if (!this.pendingReconnect) {
|
|
702
761
|
this.pendingReconnect = true;
|
|
703
|
-
Promise.resolve()
|
|
704
|
-
|
|
762
|
+
Promise.resolve()
|
|
763
|
+
.then(async () => {
|
|
764
|
+
if (this.pendingReconnect) {
|
|
765
|
+
// still valid?
|
|
705
766
|
await this.reconnect("write", // connectionMode
|
|
706
767
|
"Switch to write");
|
|
707
768
|
}
|
|
708
|
-
})
|
|
769
|
+
})
|
|
770
|
+
.catch(() => { });
|
|
709
771
|
}
|
|
710
772
|
return;
|
|
711
773
|
}
|
|
@@ -715,7 +777,8 @@ class ConnectionManager {
|
|
|
715
777
|
beforeProcessingIncomingOp(message) {
|
|
716
778
|
// if we have connection, and message is local, then we better treat is as local!
|
|
717
779
|
(0, common_utils_1.assert)(this.clientId !== message.clientId || this.lastSubmittedClientId === message.clientId, 0x0ee /* "Not accounting local messages correctly" */);
|
|
718
|
-
if (this.lastSubmittedClientId !== undefined &&
|
|
780
|
+
if (this.lastSubmittedClientId !== undefined &&
|
|
781
|
+
this.lastSubmittedClientId === message.clientId) {
|
|
719
782
|
const clientSequenceNumber = message.clientSequenceNumber;
|
|
720
783
|
(0, common_utils_1.assert)(this.clientSequenceNumberObserved < clientSequenceNumber, 0x0ef /* "client seq# not growing" */);
|
|
721
784
|
(0, common_utils_1.assert)(clientSequenceNumber <= this.clientSequenceNumber, 0x0f0 /* "Incoming local client seq# > generated by this client" */);
|