@fluidframework/container-loader 2.0.0-internal.5.4.2 → 2.0.0-internal.6.0.1
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 +81 -0
- package/dist/connectionManager.d.ts +1 -1
- package/dist/connectionManager.d.ts.map +1 -1
- package/dist/connectionManager.js +24 -25
- package/dist/connectionManager.js.map +1 -1
- package/dist/connectionStateHandler.d.ts +2 -1
- package/dist/connectionStateHandler.d.ts.map +1 -1
- package/dist/connectionStateHandler.js +9 -16
- package/dist/connectionStateHandler.js.map +1 -1
- package/dist/container.d.ts +10 -5
- package/dist/container.d.ts.map +1 -1
- package/dist/container.js +161 -99
- 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.js +3 -5
- package/dist/containerStorageAdapter.js.map +1 -1
- package/dist/contracts.d.ts +11 -2
- package/dist/contracts.d.ts.map +1 -1
- package/dist/contracts.js +3 -3
- package/dist/contracts.js.map +1 -1
- package/dist/debugLogger.js +2 -3
- package/dist/debugLogger.js.map +1 -1
- package/dist/deltaManager.d.ts +16 -3
- package/dist/deltaManager.d.ts.map +1 -1
- package/dist/deltaManager.js +62 -24
- package/dist/deltaManager.js.map +1 -1
- package/dist/deltaQueue.js +1 -2
- package/dist/deltaQueue.js.map +1 -1
- package/dist/loader.d.ts +12 -0
- package/dist/loader.d.ts.map +1 -1
- package/dist/loader.js +57 -42
- 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 -3
- package/dist/protocol.js.map +1 -1
- package/dist/utils.d.ts +8 -1
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +24 -6
- package/dist/utils.js.map +1 -1
- package/lib/connectionManager.d.ts +1 -1
- package/lib/connectionManager.d.ts.map +1 -1
- package/lib/connectionManager.js +25 -26
- package/lib/connectionManager.js.map +1 -1
- package/lib/connectionStateHandler.d.ts +2 -1
- package/lib/connectionStateHandler.d.ts.map +1 -1
- package/lib/connectionStateHandler.js +9 -16
- package/lib/connectionStateHandler.js.map +1 -1
- package/lib/container.d.ts +10 -5
- package/lib/container.d.ts.map +1 -1
- package/lib/container.js +160 -98
- 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.js +3 -5
- package/lib/containerStorageAdapter.js.map +1 -1
- package/lib/contracts.d.ts +11 -2
- package/lib/contracts.d.ts.map +1 -1
- package/lib/contracts.js +3 -3
- package/lib/contracts.js.map +1 -1
- package/lib/debugLogger.js +2 -3
- package/lib/debugLogger.js.map +1 -1
- package/lib/deltaManager.d.ts +16 -3
- package/lib/deltaManager.d.ts.map +1 -1
- package/lib/deltaManager.js +62 -24
- package/lib/deltaManager.js.map +1 -1
- package/lib/deltaQueue.js +1 -2
- package/lib/deltaQueue.js.map +1 -1
- package/lib/loader.d.ts +12 -0
- package/lib/loader.d.ts.map +1 -1
- package/lib/loader.js +57 -42
- 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 -3
- package/lib/protocol.js.map +1 -1
- package/lib/utils.d.ts +8 -1
- package/lib/utils.d.ts.map +1 -1
- package/lib/utils.js +22 -5
- package/lib/utils.js.map +1 -1
- package/package.json +14 -14
- package/src/connectionManager.ts +7 -3
- package/src/connectionStateHandler.ts +3 -2
- package/src/container.ts +113 -27
- package/src/containerContext.ts +0 -16
- package/src/contracts.ts +16 -5
- package/src/deltaManager.ts +22 -5
- package/src/loader.ts +37 -23
- package/src/packageVersion.ts +1 -1
- package/src/protocol.ts +0 -1
- package/src/utils.ts +29 -0
package/lib/container.js
CHANGED
|
@@ -8,18 +8,18 @@ import { v4 as uuid } from "uuid";
|
|
|
8
8
|
import { TypedEventEmitter, assert, performance, unreachableCase, } from "@fluidframework/common-utils";
|
|
9
9
|
import { AttachState, isFluidCodeDetails, } from "@fluidframework/container-definitions";
|
|
10
10
|
import { GenericError, UsageError } from "@fluidframework/container-utils";
|
|
11
|
-
import { readAndParse, OnlineStatus, isOnline,
|
|
11
|
+
import { readAndParse, OnlineStatus, isOnline, runWithRetry, isCombinedAppAndProtocolSummary, MessageType2, } from "@fluidframework/driver-utils";
|
|
12
12
|
import { MessageType, SummaryType, } from "@fluidframework/protocol-definitions";
|
|
13
13
|
import { createChildLogger, EventEmitterWithErrorHandling, PerformanceEvent, raiseConnectedEvent, connectedEventName, normalizeError, createChildMonitoringContext, wrapError, formatTick, } from "@fluidframework/telemetry-utils";
|
|
14
14
|
import { Audience } from "./audience";
|
|
15
15
|
import { ContainerContext } from "./containerContext";
|
|
16
|
-
import { ReconnectMode, getPackageName } from "./contracts";
|
|
16
|
+
import { ReconnectMode, getPackageName, } from "./contracts";
|
|
17
17
|
import { DeltaManager } from "./deltaManager";
|
|
18
18
|
import { RelativeLoader } from "./loader";
|
|
19
19
|
import { pkgVersion } from "./packageVersion";
|
|
20
20
|
import { ContainerStorageAdapter, getBlobContentsFromTree, getBlobContentsFromTreeWithBlobContents, } from "./containerStorageAdapter";
|
|
21
21
|
import { createConnectionStateHandler } from "./connectionStateHandler";
|
|
22
|
-
import { getProtocolSnapshotTree, getSnapshotTreeFromSerializedContainer } from "./utils";
|
|
22
|
+
import { combineAppAndProtocolSummary, getProtocolSnapshotTree, getSnapshotTreeFromSerializedContainer, } from "./utils";
|
|
23
23
|
import { initQuorumValuesFromCodeDetails } from "./quorum";
|
|
24
24
|
import { NoopHeuristic } from "./noopHeuristic";
|
|
25
25
|
import { ConnectionManager } from "./connectionManager";
|
|
@@ -104,7 +104,7 @@ export async function waitContainerToCatchUp(container) {
|
|
|
104
104
|
}
|
|
105
105
|
const getCodeProposal =
|
|
106
106
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
|
107
|
-
(quorum) =>
|
|
107
|
+
(quorum) => quorum.get("code") ?? quorum.get("code2");
|
|
108
108
|
/**
|
|
109
109
|
* Helper function to report to telemetry cases where operation takes longer than expected (200ms)
|
|
110
110
|
* @param logger - logger to use
|
|
@@ -124,7 +124,6 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
124
124
|
* @internal
|
|
125
125
|
*/
|
|
126
126
|
constructor(createProps, loadProps) {
|
|
127
|
-
var _a;
|
|
128
127
|
super((name, error) => {
|
|
129
128
|
this.mc.logger.sendErrorEvent({
|
|
130
129
|
eventName: "ContainerEventHandlerException",
|
|
@@ -174,8 +173,8 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
174
173
|
};
|
|
175
174
|
const { canReconnect, clientDetailsOverride, urlResolver, documentServiceFactory, codeLoader, options, scope, subLogger, detachedBlobStorage, protocolHandlerBuilder, } = createProps;
|
|
176
175
|
this.connectionTransitionTimes[ConnectionState.Disconnected] = performance.now();
|
|
177
|
-
const pendingLocalState = loadProps
|
|
178
|
-
this._canReconnect = canReconnect
|
|
176
|
+
const pendingLocalState = loadProps?.pendingLocalState;
|
|
177
|
+
this._canReconnect = canReconnect ?? true;
|
|
179
178
|
this.clientDetailsOverride = clientDetailsOverride;
|
|
180
179
|
this.urlResolver = urlResolver;
|
|
181
180
|
this.serviceFactory = documentServiceFactory;
|
|
@@ -183,14 +182,18 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
183
182
|
// Warning: this is only a shallow clone. Mutation of any individual loader option will mutate it for
|
|
184
183
|
// all clients that were loaded from the same loader (including summarizer clients).
|
|
185
184
|
// Tracking alternative ways to handle this in AB#4129.
|
|
186
|
-
this.options =
|
|
185
|
+
this.options = { ...options };
|
|
187
186
|
this.scope = scope;
|
|
188
187
|
this.detachedBlobStorage = detachedBlobStorage;
|
|
189
188
|
this.protocolHandlerBuilder =
|
|
190
|
-
protocolHandlerBuilder
|
|
189
|
+
protocolHandlerBuilder ??
|
|
190
|
+
((attributes, quorumSnapshot, sendProposal) => new ProtocolHandler(attributes, quorumSnapshot, sendProposal, new Audience(), (clientId) => this.clientsWhoShouldHaveLeft.has(clientId)));
|
|
191
191
|
// Note that we capture the createProps here so we can replicate the creation call when we want to clone.
|
|
192
192
|
this.clone = async (_loadProps, createParamOverrides) => {
|
|
193
|
-
return Container.load(_loadProps,
|
|
193
|
+
return Container.load(_loadProps, {
|
|
194
|
+
...createProps,
|
|
195
|
+
...createParamOverrides,
|
|
196
|
+
});
|
|
194
197
|
};
|
|
195
198
|
// Create logger for data stores to use
|
|
196
199
|
const type = this.client.details.type;
|
|
@@ -204,7 +207,7 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
204
207
|
all: {
|
|
205
208
|
clientType,
|
|
206
209
|
containerId: uuid(),
|
|
207
|
-
docId: () =>
|
|
210
|
+
docId: () => this.resolvedUrl?.id,
|
|
208
211
|
containerAttachState: () => this._attachState,
|
|
209
212
|
containerLifecycleState: () => this._lifecycleState,
|
|
210
213
|
containerConnectionState: () => ConnectionState[this.connectionState],
|
|
@@ -215,22 +218,19 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
215
218
|
// specific error or class of errors
|
|
216
219
|
error: {
|
|
217
220
|
// load information to associate errors with the specific load point
|
|
218
|
-
dmInitialSeqNumber: () =>
|
|
219
|
-
dmLastProcessedSeqNumber: () =>
|
|
220
|
-
dmLastKnownSeqNumber: () =>
|
|
221
|
-
containerLoadedFromVersionId: () =>
|
|
222
|
-
containerLoadedFromVersionDate: () =>
|
|
221
|
+
dmInitialSeqNumber: () => this._deltaManager?.initialSequenceNumber,
|
|
222
|
+
dmLastProcessedSeqNumber: () => this._deltaManager?.lastSequenceNumber,
|
|
223
|
+
dmLastKnownSeqNumber: () => this._deltaManager?.lastKnownSeqNumber,
|
|
224
|
+
containerLoadedFromVersionId: () => this._loadedFromVersion?.id,
|
|
225
|
+
containerLoadedFromVersionDate: () => this._loadedFromVersion?.date,
|
|
223
226
|
// message information to associate errors with the specific execution state
|
|
224
227
|
// dmLastMsqSeqNumber: if present, same as dmLastProcessedSeqNumber
|
|
225
|
-
dmLastMsqSeqNumber: () =>
|
|
226
|
-
dmLastMsqSeqTimestamp: () =>
|
|
227
|
-
dmLastMsqSeqClientId: () =>
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
: (_d = (_c = this.deltaManager) === null || _c === void 0 ? void 0 : _c.lastMessage) === null || _d === void 0 ? void 0 : _d.clientId;
|
|
232
|
-
},
|
|
233
|
-
dmLastMsgClientSeq: () => { var _a, _b; return (_b = (_a = this.deltaManager) === null || _a === void 0 ? void 0 : _a.lastMessage) === null || _b === void 0 ? void 0 : _b.clientSequenceNumber; },
|
|
228
|
+
dmLastMsqSeqNumber: () => this.deltaManager?.lastMessage?.sequenceNumber,
|
|
229
|
+
dmLastMsqSeqTimestamp: () => this.deltaManager?.lastMessage?.timestamp,
|
|
230
|
+
dmLastMsqSeqClientId: () => this.deltaManager?.lastMessage?.clientId === null
|
|
231
|
+
? "null"
|
|
232
|
+
: this.deltaManager?.lastMessage?.clientId,
|
|
233
|
+
dmLastMsgClientSeq: () => this.deltaManager?.lastMessage?.clientSequenceNumber,
|
|
234
234
|
connectionStateDuration: () => performance.now() - this.connectionTransitionTimes[this.connectionState],
|
|
235
235
|
},
|
|
236
236
|
},
|
|
@@ -260,9 +260,14 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
260
260
|
// Report issues only if we already loaded container - op processing is paused while container is loading,
|
|
261
261
|
// so we always time-out processing of join op in cases where fetching snapshot takes a minute.
|
|
262
262
|
// It's not a problem with op processing itself - such issues should be tracked as part of boot perf monitoring instead.
|
|
263
|
-
this._deltaManager.logConnectionIssue(
|
|
264
|
-
|
|
265
|
-
|
|
263
|
+
this._deltaManager.logConnectionIssue({
|
|
264
|
+
eventName,
|
|
265
|
+
mode,
|
|
266
|
+
category: this._lifecycleState === "loading" ? "generic" : category,
|
|
267
|
+
duration: performance.now() -
|
|
268
|
+
this.connectionTransitionTimes[ConnectionState.CatchingUp],
|
|
269
|
+
...(details === undefined ? {} : { details: JSON.stringify(details) }),
|
|
270
|
+
});
|
|
266
271
|
// If this is "write" connection, it took too long to receive join op. But in most cases that's due
|
|
267
272
|
// to very slow op fetches and we will eventually get there.
|
|
268
273
|
// For "read" connections, we get here due to self join signal not arriving on time. We will need to
|
|
@@ -279,7 +284,7 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
279
284
|
clientShouldHaveLeft: (clientId) => {
|
|
280
285
|
this.clientsWhoShouldHaveLeft.add(clientId);
|
|
281
286
|
},
|
|
282
|
-
}, this.deltaManager, pendingLocalState
|
|
287
|
+
}, this.deltaManager, pendingLocalState?.clientId);
|
|
283
288
|
this.on(savedContainerEvent, () => {
|
|
284
289
|
this.connectionStateHandler.containerSaved();
|
|
285
290
|
});
|
|
@@ -291,8 +296,9 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
291
296
|
: combineAppAndProtocolSummary(summaryTree, this.captureProtocolSummary());
|
|
292
297
|
// Whether the combined summary tree has been forced on by either the loader option or the monitoring context.
|
|
293
298
|
// Even if not forced on via this flag, combined summaries may still be enabled by service policy.
|
|
294
|
-
const forceEnableSummarizeProtocolTree =
|
|
295
|
-
|
|
299
|
+
const forceEnableSummarizeProtocolTree = this.mc.config.getBoolean("Fluid.Container.summarizeProtocolTree2") ??
|
|
300
|
+
options.summarizeProtocolTree;
|
|
301
|
+
this.storageAdapter = new ContainerStorageAdapter(detachedBlobStorage, this.mc.logger, pendingLocalState?.snapshotBlobs, addProtocolSummaryIfMissing, forceEnableSummarizeProtocolTree);
|
|
296
302
|
const isDomAvailable = typeof document === "object" &&
|
|
297
303
|
document !== null &&
|
|
298
304
|
typeof document.addEventListener === "function" &&
|
|
@@ -319,7 +325,7 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
319
325
|
* @internal
|
|
320
326
|
*/
|
|
321
327
|
static async load(loadProps, createProps) {
|
|
322
|
-
const { version, pendingLocalState, loadMode, resolvedUrl } = loadProps;
|
|
328
|
+
const { version, pendingLocalState, loadMode, resolvedUrl, loadToSequenceNumber } = loadProps;
|
|
323
329
|
const container = new Container(createProps, loadProps);
|
|
324
330
|
const disableRecordHeapSize = container.mc.config.getBoolean("Fluid.Loader.DisableRecordHeapSize");
|
|
325
331
|
return PerformanceEvent.timedExecAsync(container.mc.logger, { eventName: "Load" }, async (event) => new Promise((resolve, reject) => {
|
|
@@ -327,19 +333,20 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
327
333
|
// if we have pendingLocalState, anything we cached is not useful and we shouldn't wait for connection
|
|
328
334
|
// to return container, so ignore this value and use undefined for opsBeforeReturn
|
|
329
335
|
const mode = pendingLocalState
|
|
330
|
-
?
|
|
336
|
+
? { ...(loadMode ?? defaultMode), opsBeforeReturn: undefined }
|
|
337
|
+
: loadMode ?? defaultMode;
|
|
331
338
|
const onClosed = (err) => {
|
|
332
339
|
// pre-0.58 error message: containerClosedWithoutErrorDuringLoad
|
|
333
|
-
reject(err
|
|
340
|
+
reject(err ?? new GenericError("Container closed without error during load"));
|
|
334
341
|
};
|
|
335
342
|
container.on("closed", onClosed);
|
|
336
343
|
container
|
|
337
|
-
.load(version, mode, resolvedUrl, pendingLocalState)
|
|
344
|
+
.load(version, mode, resolvedUrl, pendingLocalState, loadToSequenceNumber)
|
|
338
345
|
.finally(() => {
|
|
339
346
|
container.removeListener("closed", onClosed);
|
|
340
347
|
})
|
|
341
348
|
.then((props) => {
|
|
342
|
-
event.end(
|
|
349
|
+
event.end({ ...props, ...loadMode });
|
|
343
350
|
resolve(container);
|
|
344
351
|
}, (error) => {
|
|
345
352
|
const err = normalizeError(error);
|
|
@@ -407,7 +414,6 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
407
414
|
return this;
|
|
408
415
|
}
|
|
409
416
|
get resolvedUrl() {
|
|
410
|
-
var _a;
|
|
411
417
|
/**
|
|
412
418
|
* All attached containers will have a document service,
|
|
413
419
|
* this is required, as attached containers are attached to
|
|
@@ -419,7 +425,7 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
419
425
|
* is always the same as the containers, as we had to
|
|
420
426
|
* obtain the resolved url, and then create the service from it.
|
|
421
427
|
*/
|
|
422
|
-
return
|
|
428
|
+
return this.service?.resolvedUrl;
|
|
423
429
|
}
|
|
424
430
|
get readOnlyInfo() {
|
|
425
431
|
return this._deltaManager.readOnlyInfo;
|
|
@@ -447,8 +453,8 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
447
453
|
return this._clientId;
|
|
448
454
|
}
|
|
449
455
|
get offlineLoadEnabled() {
|
|
450
|
-
|
|
451
|
-
|
|
456
|
+
const enabled = this.mc.config.getBoolean("Fluid.Container.enableOfflineLoad") ??
|
|
457
|
+
this.options?.enableOfflineLoad === true;
|
|
452
458
|
// summarizer will not have any pending state we want to save
|
|
453
459
|
return enabled && this.deltaManager.clientDetails.capabilities.interactive;
|
|
454
460
|
}
|
|
@@ -485,18 +491,16 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
485
491
|
* {@inheritDoc @fluidframework/container-definitions#IContainer.entryPoint}
|
|
486
492
|
*/
|
|
487
493
|
async getEntryPoint() {
|
|
488
|
-
var _a, _b;
|
|
489
494
|
if (this._disposed) {
|
|
490
495
|
throw new UsageError("The context is already disposed");
|
|
491
496
|
}
|
|
492
497
|
if (this._runtime !== undefined) {
|
|
493
|
-
return
|
|
498
|
+
return this._runtime.getEntryPoint?.();
|
|
494
499
|
}
|
|
495
500
|
return new Promise((resolve, reject) => {
|
|
496
501
|
const runtimeInstantiatedHandler = () => {
|
|
497
|
-
var _a, _b;
|
|
498
502
|
assert(this._runtime !== undefined, 0x5a3 /* runtimeInstantiated fired but runtime is still undefined */);
|
|
499
|
-
resolve(
|
|
503
|
+
resolve(this._runtime.getEntryPoint?.());
|
|
500
504
|
this._lifecycleEvents.off("disposed", disposedHandler);
|
|
501
505
|
};
|
|
502
506
|
const disposedHandler = () => {
|
|
@@ -530,7 +534,6 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
530
534
|
assert(this._lifecycleState === "closed" || this._lifecycleState === "disposed", 0x314 /* Container properly closed */);
|
|
531
535
|
}
|
|
532
536
|
closeCore(error) {
|
|
533
|
-
var _a;
|
|
534
537
|
assert(!this.closed, 0x315 /* re-entrancy */);
|
|
535
538
|
try {
|
|
536
539
|
// Ensure that we raise all key events even if one of these throws
|
|
@@ -546,7 +549,7 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
546
549
|
: "generic",
|
|
547
550
|
}, error);
|
|
548
551
|
this._lifecycleState = "closing";
|
|
549
|
-
|
|
552
|
+
this._protocolHandler?.close();
|
|
550
553
|
this.connectionStateHandler.dispose();
|
|
551
554
|
}
|
|
552
555
|
catch (exception) {
|
|
@@ -566,7 +569,6 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
566
569
|
}
|
|
567
570
|
}
|
|
568
571
|
disposeCore(error) {
|
|
569
|
-
var _a, _b, _c;
|
|
570
572
|
assert(!this._disposed, 0x54c /* Container already disposed */);
|
|
571
573
|
this._disposed = true;
|
|
572
574
|
try {
|
|
@@ -583,15 +585,15 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
583
585
|
if (this._lifecycleState !== "closed") {
|
|
584
586
|
this._lifecycleState = "disposing";
|
|
585
587
|
}
|
|
586
|
-
|
|
588
|
+
this._protocolHandler?.close();
|
|
587
589
|
this.connectionStateHandler.dispose();
|
|
588
590
|
const maybeError = error !== undefined ? new Error(error.message) : undefined;
|
|
589
|
-
|
|
591
|
+
this._runtime?.dispose(maybeError);
|
|
590
592
|
this.storageAdapter.dispose();
|
|
591
593
|
// Notify storage about critical errors. They may be due to disconnect between client & server knowledge
|
|
592
594
|
// about file, like file being overwritten in storage, but client having stale local cache.
|
|
593
595
|
// Driver need to ensure all caches are cleared on critical errors
|
|
594
|
-
|
|
596
|
+
this.service?.dispose(error);
|
|
595
597
|
}
|
|
596
598
|
catch (exception) {
|
|
597
599
|
this.mc.logger.sendErrorEvent({ eventName: "ContainerDisposeException" }, exception);
|
|
@@ -607,15 +609,19 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
607
609
|
this._lifecycleEvents.emit("disposed");
|
|
608
610
|
}
|
|
609
611
|
}
|
|
610
|
-
closeAndGetPendingLocalState() {
|
|
612
|
+
async closeAndGetPendingLocalState() {
|
|
611
613
|
// runtime matches pending ops to successful ones by clientId and client seq num, so we need to close the
|
|
612
614
|
// container at the same time we get pending state, otherwise this container could reconnect and resubmit with
|
|
613
615
|
// a new clientId and a future container using stale pending state without the new clientId would resubmit them
|
|
614
|
-
|
|
616
|
+
this.disconnect(); // TODO https://dev.azure.com/fluidframework/internal/_workitems/edit/5127
|
|
617
|
+
const pendingState = await this.getPendingLocalStateCore({ notifyImminentClosure: true });
|
|
615
618
|
this.close();
|
|
616
619
|
return pendingState;
|
|
617
620
|
}
|
|
618
|
-
getPendingLocalState() {
|
|
621
|
+
async getPendingLocalState() {
|
|
622
|
+
return this.getPendingLocalStateCore({ notifyImminentClosure: false });
|
|
623
|
+
}
|
|
624
|
+
async getPendingLocalStateCore(props) {
|
|
619
625
|
if (!this.offlineLoadEnabled) {
|
|
620
626
|
throw new UsageError("Can't get pending local state unless offline load is enabled");
|
|
621
627
|
}
|
|
@@ -626,8 +632,9 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
626
632
|
assert(this.resolvedUrl !== undefined && this.resolvedUrl.type === "fluid", 0x0d2 /* "resolved url should be valid Fluid url" */);
|
|
627
633
|
assert(!!this.baseSnapshot, 0x5d4 /* no base snapshot */);
|
|
628
634
|
assert(!!this.baseSnapshotBlobs, 0x5d5 /* no snapshot blobs */);
|
|
635
|
+
const pendingRuntimeState = await this.runtime.getPendingLocalState(props);
|
|
629
636
|
const pendingState = {
|
|
630
|
-
pendingRuntimeState
|
|
637
|
+
pendingRuntimeState,
|
|
631
638
|
baseSnapshot: this.baseSnapshot,
|
|
632
639
|
snapshotBlobs: this.baseSnapshotBlobs,
|
|
633
640
|
savedOps: this.savedOps,
|
|
@@ -656,7 +663,6 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
656
663
|
}
|
|
657
664
|
async attach(request) {
|
|
658
665
|
await PerformanceEvent.timedExecAsync(this.mc.logger, { eventName: "Attach" }, async () => {
|
|
659
|
-
var _a;
|
|
660
666
|
if (this._lifecycleState !== "loaded") {
|
|
661
667
|
// pre-0.58 error message: containerNotValidForAttach
|
|
662
668
|
throw new UsageError(`The Container is not in a valid state for attach [${this._lifecycleState}]`);
|
|
@@ -748,7 +754,7 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
748
754
|
catch (error) {
|
|
749
755
|
// add resolved URL on error object so that host has the ability to find this document and delete it
|
|
750
756
|
const newError = normalizeError(error);
|
|
751
|
-
newError.addTelemetryProperties({ resolvedUrl:
|
|
757
|
+
newError.addTelemetryProperties({ resolvedUrl: this.resolvedUrl?.url });
|
|
752
758
|
this.close(newError);
|
|
753
759
|
throw newError;
|
|
754
760
|
}
|
|
@@ -855,7 +861,6 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
855
861
|
* Determines if the currently loaded module satisfies the incoming constraint code details
|
|
856
862
|
*/
|
|
857
863
|
async satisfies(constraintCodeDetails) {
|
|
858
|
-
var _a, _b;
|
|
859
864
|
// If we have no module, it can't satisfy anything.
|
|
860
865
|
if (this._loadedModule === undefined) {
|
|
861
866
|
return false;
|
|
@@ -865,8 +870,8 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
865
870
|
if (maybeCompareCodeLoader.IFluidCodeDetailsComparer !== undefined) {
|
|
866
871
|
comparers.push(maybeCompareCodeLoader.IFluidCodeDetailsComparer);
|
|
867
872
|
}
|
|
868
|
-
const maybeCompareExport =
|
|
869
|
-
if (
|
|
873
|
+
const maybeCompareExport = this._loadedModule?.module.fluidExport;
|
|
874
|
+
if (maybeCompareExport?.IFluidCodeDetailsComparer !== undefined) {
|
|
870
875
|
comparers.push(maybeCompareExport.IFluidCodeDetailsComparer);
|
|
871
876
|
}
|
|
872
877
|
// If there are no comparers, then it's impossible to know if the currently loaded package satisfies
|
|
@@ -876,7 +881,7 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
876
881
|
return false;
|
|
877
882
|
}
|
|
878
883
|
for (const comparer of comparers) {
|
|
879
|
-
const satisfies = await comparer.satisfies(
|
|
884
|
+
const satisfies = await comparer.satisfies(this._loadedModule?.details, constraintCodeDetails);
|
|
880
885
|
if (satisfies === false) {
|
|
881
886
|
return false;
|
|
882
887
|
}
|
|
@@ -899,8 +904,7 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
899
904
|
*
|
|
900
905
|
* @param specifiedVersion - Version SHA to load snapshot. If not specified, will fetch the latest snapshot.
|
|
901
906
|
*/
|
|
902
|
-
async load(specifiedVersion, loadMode, resolvedUrl, pendingLocalState) {
|
|
903
|
-
var _a, _b, _c;
|
|
907
|
+
async load(specifiedVersion, loadMode, resolvedUrl, pendingLocalState, loadToSequenceNumber) {
|
|
904
908
|
this.service = await this.serviceFactory.createDocumentService(resolvedUrl, this.subLogger, this.client.details.type === summarizerClientType);
|
|
905
909
|
// Ideally we always connect as "read" by default.
|
|
906
910
|
// Currently that works with SPO & r11s, because we get "write" connection when connecting to non-existing file.
|
|
@@ -949,9 +953,51 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
949
953
|
}
|
|
950
954
|
const attributes = await this.getDocumentAttributes(this.storageAdapter, snapshot);
|
|
951
955
|
// If we saved ops, we will replay them and don't need DeltaManager to fetch them
|
|
952
|
-
const sequenceNumber =
|
|
953
|
-
const dmAttributes = sequenceNumber !== undefined ?
|
|
956
|
+
const sequenceNumber = pendingLocalState?.savedOps[pendingLocalState.savedOps.length - 1]?.sequenceNumber;
|
|
957
|
+
const dmAttributes = sequenceNumber !== undefined ? { ...attributes, sequenceNumber } : attributes;
|
|
954
958
|
let opsBeforeReturnP;
|
|
959
|
+
if (loadMode.pauseAfterLoad === true) {
|
|
960
|
+
// If we are trying to pause at a specific sequence number, ensure the latest snapshot is not newer than the desired sequence number.
|
|
961
|
+
if (loadMode.opsBeforeReturn === "sequenceNumber") {
|
|
962
|
+
assert(loadToSequenceNumber !== undefined, 0x727 /* sequenceNumber should be defined */);
|
|
963
|
+
// Note: It is possible that we think the latest snapshot is newer than the specified sequence number
|
|
964
|
+
// due to saved ops that may be replayed after the snapshot.
|
|
965
|
+
// https://dev.azure.com/fluidframework/internal/_workitems/edit/5055
|
|
966
|
+
if (dmAttributes.sequenceNumber > loadToSequenceNumber) {
|
|
967
|
+
throw new Error("Cannot satisfy request to pause the container at the specified sequence number. Most recent snapshot is newer than the specified sequence number.");
|
|
968
|
+
}
|
|
969
|
+
}
|
|
970
|
+
// Force readonly mode - this will ensure we don't receive an error for the lack of join op
|
|
971
|
+
this.forceReadonly(true);
|
|
972
|
+
// We need to setup a listener to stop op processing once we reach the desired sequence number (if specified).
|
|
973
|
+
const opHandler = () => {
|
|
974
|
+
if (loadToSequenceNumber === undefined) {
|
|
975
|
+
// If there is no specified sequence number, pause after the inbound queue is empty.
|
|
976
|
+
if (this.deltaManager.inbound.length !== 0) {
|
|
977
|
+
return;
|
|
978
|
+
}
|
|
979
|
+
}
|
|
980
|
+
else {
|
|
981
|
+
// If there is a specified sequence number, keep processing until we reach it.
|
|
982
|
+
if (this.deltaManager.lastSequenceNumber < loadToSequenceNumber) {
|
|
983
|
+
return;
|
|
984
|
+
}
|
|
985
|
+
}
|
|
986
|
+
// Pause op processing once we have processed the desired number of ops.
|
|
987
|
+
void this.deltaManager.inbound.pause();
|
|
988
|
+
void this.deltaManager.outbound.pause();
|
|
989
|
+
this.off("op", opHandler);
|
|
990
|
+
};
|
|
991
|
+
if ((loadToSequenceNumber === undefined && this.deltaManager.inbound.length === 0) ||
|
|
992
|
+
this.deltaManager.lastSequenceNumber === loadToSequenceNumber) {
|
|
993
|
+
// If we have already reached the desired sequence number, call opHandler() to pause immediately.
|
|
994
|
+
opHandler();
|
|
995
|
+
}
|
|
996
|
+
else {
|
|
997
|
+
// If we have not yet reached the desired sequence number, setup a listener to pause once we reach it.
|
|
998
|
+
this.on("op", opHandler);
|
|
999
|
+
}
|
|
1000
|
+
}
|
|
955
1001
|
// Attach op handlers to finish initialization and be able to start processing ops
|
|
956
1002
|
// Kick off any ops fetching if required.
|
|
957
1003
|
switch (loadMode.opsBeforeReturn) {
|
|
@@ -960,6 +1006,9 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
960
1006
|
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
|
961
1007
|
this.attachDeltaManagerOpHandler(dmAttributes, loadMode.deltaConnection !== "none" ? "all" : "none");
|
|
962
1008
|
break;
|
|
1009
|
+
case "sequenceNumber":
|
|
1010
|
+
opsBeforeReturnP = this.attachDeltaManagerOpHandler(dmAttributes, "sequenceNumber");
|
|
1011
|
+
break;
|
|
963
1012
|
case "cached":
|
|
964
1013
|
opsBeforeReturnP = this.attachDeltaManagerOpHandler(dmAttributes, "cached");
|
|
965
1014
|
break;
|
|
@@ -973,18 +1022,18 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
973
1022
|
// Initialize the protocol handler
|
|
974
1023
|
await this.initializeProtocolStateFromSnapshot(attributes, this.storageAdapter, snapshot);
|
|
975
1024
|
const codeDetails = this.getCodeDetailsFromQuorum();
|
|
976
|
-
await this.instantiateRuntime(codeDetails, snapshot, pendingLocalState
|
|
1025
|
+
await this.instantiateRuntime(codeDetails, snapshot, pendingLocalState?.pendingRuntimeState);
|
|
977
1026
|
// replay saved ops
|
|
978
1027
|
if (pendingLocalState) {
|
|
979
1028
|
for (const message of pendingLocalState.savedOps) {
|
|
980
1029
|
this.processRemoteMessage(message);
|
|
981
1030
|
// allow runtime to apply stashed ops at this op's sequence number
|
|
982
|
-
await
|
|
1031
|
+
await this.runtime.notifyOpReplay?.(message);
|
|
983
1032
|
}
|
|
984
1033
|
pendingLocalState.savedOps = [];
|
|
985
1034
|
// now set clientId to stashed clientId so live ops are correctly processed as local
|
|
986
1035
|
assert(this.clientId === undefined, 0x5d6 /* Unexpected clientId when setting stashed clientId */);
|
|
987
|
-
this._clientId = pendingLocalState
|
|
1036
|
+
this._clientId = pendingLocalState?.clientId;
|
|
988
1037
|
}
|
|
989
1038
|
// We might have hit some failure that did not manifest itself in exception in this flow,
|
|
990
1039
|
// do not start op processing in such case - static version of Container.load() will handle it correctly.
|
|
@@ -1015,6 +1064,19 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
1015
1064
|
unreachableCase(loadMode.deltaConnection);
|
|
1016
1065
|
}
|
|
1017
1066
|
}
|
|
1067
|
+
// If we have not yet reached `loadToSequenceNumber`, we will wait for ops to arrive until we reach it
|
|
1068
|
+
if (loadToSequenceNumber !== undefined &&
|
|
1069
|
+
this.deltaManager.lastSequenceNumber < loadToSequenceNumber) {
|
|
1070
|
+
await new Promise((resolve, reject) => {
|
|
1071
|
+
const opHandler = (message) => {
|
|
1072
|
+
if (message.sequenceNumber >= loadToSequenceNumber) {
|
|
1073
|
+
resolve();
|
|
1074
|
+
this.off("op", opHandler);
|
|
1075
|
+
}
|
|
1076
|
+
};
|
|
1077
|
+
this.on("op", opHandler);
|
|
1078
|
+
});
|
|
1079
|
+
}
|
|
1018
1080
|
// Safety net: static version of Container.load() should have learned about it through "closed" handler.
|
|
1019
1081
|
// But if that did not happen for some reason, fail load for sure.
|
|
1020
1082
|
// Otherwise we can get into situations where container is closed and does not try to connect to ordering
|
|
@@ -1169,8 +1231,7 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
1169
1231
|
return pkg;
|
|
1170
1232
|
}
|
|
1171
1233
|
get client() {
|
|
1172
|
-
|
|
1173
|
-
const client = ((_a = this.options) === null || _a === void 0 ? void 0 : _a.client) !== undefined
|
|
1234
|
+
const client = this.options?.client !== undefined
|
|
1174
1235
|
? this.options.client
|
|
1175
1236
|
: {
|
|
1176
1237
|
details: {
|
|
@@ -1218,8 +1279,7 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
1218
1279
|
this.connectionStateHandler.cancelEstablishingConnection(reason);
|
|
1219
1280
|
});
|
|
1220
1281
|
deltaManager.on("disconnect", (reason, error) => {
|
|
1221
|
-
|
|
1222
|
-
(_a = this.noopHeuristic) === null || _a === void 0 ? void 0 : _a.notifyDisconnect();
|
|
1282
|
+
this.noopHeuristic?.notifyDisconnect();
|
|
1223
1283
|
if (!this.closed) {
|
|
1224
1284
|
this.connectionStateHandler.receivedDisconnectEvent(reason, error);
|
|
1225
1285
|
}
|
|
@@ -1254,7 +1314,6 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
1254
1314
|
}, prefetchType);
|
|
1255
1315
|
}
|
|
1256
1316
|
logConnectionStateChangeTelemetry(value, oldState, reason, error) {
|
|
1257
|
-
var _a;
|
|
1258
1317
|
// Log actual event
|
|
1259
1318
|
const time = performance.now();
|
|
1260
1319
|
this.connectionTransitionTimes[value] = time;
|
|
@@ -1284,19 +1343,31 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
1284
1343
|
}
|
|
1285
1344
|
connectionInitiationReason = this.firstConnection ? "InitialConnect" : "AutoReconnect";
|
|
1286
1345
|
}
|
|
1287
|
-
this.mc.logger.sendPerformanceEvent(
|
|
1346
|
+
this.mc.logger.sendPerformanceEvent({
|
|
1347
|
+
eventName: `ConnectionStateChange_${ConnectionState[value]}`,
|
|
1348
|
+
from: ConnectionState[oldState],
|
|
1349
|
+
duration,
|
|
1288
1350
|
durationFromDisconnected,
|
|
1289
1351
|
reason,
|
|
1290
|
-
connectionInitiationReason,
|
|
1291
|
-
|
|
1352
|
+
connectionInitiationReason,
|
|
1353
|
+
pendingClientId: this.connectionStateHandler.pendingClientId,
|
|
1354
|
+
clientId: this.clientId,
|
|
1355
|
+
autoReconnect,
|
|
1356
|
+
opsBehind,
|
|
1357
|
+
online: OnlineStatus[isOnline()],
|
|
1358
|
+
lastVisible: this.lastVisible !== undefined
|
|
1292
1359
|
? performance.now() - this.lastVisible
|
|
1293
|
-
: undefined,
|
|
1360
|
+
: undefined,
|
|
1361
|
+
checkpointSequenceNumber,
|
|
1362
|
+
quorumSize: this._protocolHandler?.quorum.getMembers().size,
|
|
1363
|
+
isDirty: this.isDirty,
|
|
1364
|
+
...this._deltaManager.connectionProps,
|
|
1365
|
+
}, error);
|
|
1294
1366
|
if (value === ConnectionState.Connected) {
|
|
1295
1367
|
this.firstConnection = false;
|
|
1296
1368
|
}
|
|
1297
1369
|
}
|
|
1298
1370
|
propagateConnectionState(initialTransition, disconnectedReason) {
|
|
1299
|
-
var _a;
|
|
1300
1371
|
// When container loaded, we want to propagate initial connection state.
|
|
1301
1372
|
// After that, we communicate only transitions to Connected & Disconnected states, skipping all other states.
|
|
1302
1373
|
// This can be changed in the future, for example we likely should add "CatchingUp" event on Container.
|
|
@@ -1307,7 +1378,7 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
1307
1378
|
}
|
|
1308
1379
|
const state = this.connectionState === ConnectionState.Connected;
|
|
1309
1380
|
// Both protocol and context should not be undefined if we got so far.
|
|
1310
|
-
this.setContextConnectedState(state,
|
|
1381
|
+
this.setContextConnectedState(state, this.readOnlyInfo.readonly ?? false);
|
|
1311
1382
|
this.protocolHandler.setConnectionState(state, this.clientId);
|
|
1312
1383
|
raiseConnectedEvent(this.mc.logger, this, state, this.clientId, disconnectedReason);
|
|
1313
1384
|
}
|
|
@@ -1347,12 +1418,11 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
1347
1418
|
return this.submitMessage(MessageType.Summarize, JSON.stringify(summary), false /* batch */, undefined /* metadata */, undefined /* compression */, referenceSequenceNumber);
|
|
1348
1419
|
}
|
|
1349
1420
|
submitMessage(type, contents, batch, metadata, compression, referenceSequenceNumber) {
|
|
1350
|
-
var _a;
|
|
1351
1421
|
if (this.connectionState !== ConnectionState.Connected) {
|
|
1352
1422
|
this.mc.logger.sendErrorEvent({ eventName: "SubmitMessageWithNoConnection", type });
|
|
1353
1423
|
return -1;
|
|
1354
1424
|
}
|
|
1355
|
-
|
|
1425
|
+
this.noopHeuristic?.notifyMessageSent();
|
|
1356
1426
|
return this._deltaManager.submit(type, contents, batch, metadata, compression, referenceSequenceNumber);
|
|
1357
1427
|
}
|
|
1358
1428
|
processRemoteMessage(message) {
|
|
@@ -1410,8 +1480,7 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
1410
1480
|
* @returns The snapshot requested, or the latest snapshot if no version was specified, plus version ID
|
|
1411
1481
|
*/
|
|
1412
1482
|
async fetchSnapshotTree(specifiedVersion) {
|
|
1413
|
-
|
|
1414
|
-
const version = await this.getVersion(specifiedVersion !== null && specifiedVersion !== void 0 ? specifiedVersion : null);
|
|
1483
|
+
const version = await this.getVersion(specifiedVersion ?? null);
|
|
1415
1484
|
if (version === undefined && specifiedVersion !== undefined) {
|
|
1416
1485
|
// We should have a defined version to load from if specified version requested
|
|
1417
1486
|
this.mc.logger.sendErrorEvent({
|
|
@@ -1420,15 +1489,14 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
1420
1489
|
});
|
|
1421
1490
|
}
|
|
1422
1491
|
this._loadedFromVersion = version;
|
|
1423
|
-
const snapshot = (
|
|
1492
|
+
const snapshot = (await this.storageAdapter.getSnapshotTree(version)) ?? undefined;
|
|
1424
1493
|
if (snapshot === undefined && version !== undefined) {
|
|
1425
1494
|
this.mc.logger.sendErrorEvent({ eventName: "getSnapshotTreeFailed", id: version.id });
|
|
1426
1495
|
}
|
|
1427
|
-
return { snapshot, versionId: version
|
|
1496
|
+
return { snapshot, versionId: version?.id };
|
|
1428
1497
|
}
|
|
1429
1498
|
async instantiateRuntime(codeDetails, snapshot, pendingLocalState) {
|
|
1430
|
-
|
|
1431
|
-
assert(((_a = this._runtime) === null || _a === void 0 ? void 0 : _a.disposed) !== false, 0x0dd /* "Existing runtime not disposed" */);
|
|
1499
|
+
assert(this._runtime?.disposed !== false, 0x0dd /* "Existing runtime not disposed" */);
|
|
1432
1500
|
// The relative loader will proxy requests to '/' to the loader itself assuming no non-cache flags
|
|
1433
1501
|
// are set. Global requests will still go directly to the loader
|
|
1434
1502
|
const maybeLoader = this.scope;
|
|
@@ -1439,22 +1507,17 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
1439
1507
|
// An older interface ICodeLoader could return an IFluidModule which didn't have details.
|
|
1440
1508
|
// If we're using one of those older ICodeLoaders, then we fix up the module with the specified details here.
|
|
1441
1509
|
// TODO: Determine if this is still a realistic scenario or if this fixup could be removed.
|
|
1442
|
-
details:
|
|
1510
|
+
details: loadCodeResult.details ?? codeDetails,
|
|
1443
1511
|
};
|
|
1444
1512
|
const fluidExport = this._loadedModule.module.fluidExport;
|
|
1445
|
-
const runtimeFactory = fluidExport
|
|
1513
|
+
const runtimeFactory = fluidExport?.IRuntimeFactory;
|
|
1446
1514
|
if (runtimeFactory === undefined) {
|
|
1447
1515
|
throw new Error(packageNotFactoryError);
|
|
1448
1516
|
}
|
|
1449
|
-
const getSpecifiedCodeDetails = () =>
|
|
1450
|
-
|
|
1451
|
-
return ((_a = this.protocolHandler.quorum.get("code")) !== null && _a !== void 0 ? _a : this.protocolHandler.quorum.get("code2"));
|
|
1452
|
-
};
|
|
1517
|
+
const getSpecifiedCodeDetails = () => (this.protocolHandler.quorum.get("code") ??
|
|
1518
|
+
this.protocolHandler.quorum.get("code2"));
|
|
1453
1519
|
const existing = snapshot !== undefined;
|
|
1454
|
-
const context = new ContainerContext(this.options, this.scope, snapshot, this._loadedFromVersion, this._deltaManager, this.storageAdapter, this.protocolHandler.quorum, this.protocolHandler.audience, loader, (type, contents, batch, metadata) => this.submitContainerMessage(type, contents, batch, metadata), (summaryOp, referenceSequenceNumber) => this.submitSummaryMessage(summaryOp, referenceSequenceNumber), (batch, referenceSequenceNumber) => this.submitBatch(batch, referenceSequenceNumber), (message) => this.submitSignal(message), (error) => this.dispose(error), (error) => this.close(error), this.updateDirtyContainerState, this.getAbsoluteUrl, () =>
|
|
1455
|
-
this._lifecycleEvents.once("disposed", () => {
|
|
1456
|
-
context.dispose();
|
|
1457
|
-
});
|
|
1520
|
+
const context = new ContainerContext(this.options, this.scope, snapshot, this._loadedFromVersion, this._deltaManager, this.storageAdapter, this.protocolHandler.quorum, this.protocolHandler.audience, loader, (type, contents, batch, metadata) => this.submitContainerMessage(type, contents, batch, metadata), (summaryOp, referenceSequenceNumber) => this.submitSummaryMessage(summaryOp, referenceSequenceNumber), (batch, referenceSequenceNumber) => this.submitBatch(batch, referenceSequenceNumber), (message) => this.submitSignal(message), (error) => this.dispose(error), (error) => this.close(error), this.updateDirtyContainerState, this.getAbsoluteUrl, () => this.resolvedUrl?.id, () => this.clientId, () => this.attachState, () => this.connected, getSpecifiedCodeDetails, this._deltaManager.clientDetails, existing, this.subLogger, pendingLocalState);
|
|
1458
1521
|
this._runtime = await PerformanceEvent.timedExecAsync(this.subLogger, { eventName: "InstantiateRuntime" }, async () => runtimeFactory.instantiateRuntime(context, existing));
|
|
1459
1522
|
this._lifecycleEvents.emit("runtimeInstantiated");
|
|
1460
1523
|
this._loadedCodeDetails = codeDetails;
|
|
@@ -1466,8 +1529,7 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
1466
1529
|
* @param readonly - Is the container in readonly mode?
|
|
1467
1530
|
*/
|
|
1468
1531
|
setContextConnectedState(state, readonly) {
|
|
1469
|
-
|
|
1470
|
-
if (((_a = this._runtime) === null || _a === void 0 ? void 0 : _a.disposed) === false) {
|
|
1532
|
+
if (this._runtime?.disposed === false) {
|
|
1471
1533
|
/**
|
|
1472
1534
|
* We want to lie to the ContainerRuntime when we are in readonly mode to prevent issues with pending
|
|
1473
1535
|
* ops getting through to the DeltaManager.
|