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