@fluidframework/container-loader 2.0.0-dev.4.4.0.162574 → 2.0.0-dev.5.2.0.169897
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 +28 -0
- package/README.md +27 -3
- package/dist/connectionManager.d.ts +3 -2
- package/dist/connectionManager.d.ts.map +1 -1
- package/dist/connectionManager.js +32 -13
- package/dist/connectionManager.js.map +1 -1
- package/dist/connectionStateHandler.d.ts +15 -3
- package/dist/connectionStateHandler.d.ts.map +1 -1
- package/dist/connectionStateHandler.js +24 -1
- package/dist/connectionStateHandler.js.map +1 -1
- package/dist/container.d.ts +74 -44
- package/dist/container.d.ts.map +1 -1
- package/dist/container.js +81 -111
- package/dist/container.js.map +1 -1
- package/dist/containerContext.d.ts +2 -2
- package/dist/containerContext.d.ts.map +1 -1
- package/dist/containerContext.js +3 -7
- package/dist/containerContext.js.map +1 -1
- package/dist/containerStorageAdapter.d.ts +3 -3
- package/dist/containerStorageAdapter.d.ts.map +1 -1
- package/dist/containerStorageAdapter.js +6 -15
- package/dist/containerStorageAdapter.js.map +1 -1
- package/dist/contracts.d.ts +8 -0
- package/dist/contracts.d.ts.map +1 -1
- package/dist/contracts.js.map +1 -1
- package/dist/deltaManager.d.ts +21 -9
- package/dist/deltaManager.d.ts.map +1 -1
- package/dist/deltaManager.js +42 -31
- package/dist/deltaManager.js.map +1 -1
- package/dist/deltaQueue.d.ts +2 -3
- package/dist/deltaQueue.d.ts.map +1 -1
- package/dist/deltaQueue.js +2 -3
- package/dist/deltaQueue.js.map +1 -1
- package/dist/index.d.ts +1 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/loader.d.ts +9 -7
- package/dist/loader.d.ts.map +1 -1
- package/dist/loader.js +47 -61
- 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/retriableDocumentStorageService.d.ts +3 -2
- package/dist/retriableDocumentStorageService.d.ts.map +1 -1
- package/dist/retriableDocumentStorageService.js.map +1 -1
- package/dist/tsdoc-metadata.json +11 -0
- package/dist/utils.d.ts +2 -0
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +8 -1
- package/dist/utils.js.map +1 -1
- package/lib/connectionManager.d.ts +3 -2
- package/lib/connectionManager.d.ts.map +1 -1
- package/lib/connectionManager.js +33 -14
- package/lib/connectionManager.js.map +1 -1
- package/lib/connectionStateHandler.d.ts +15 -3
- package/lib/connectionStateHandler.d.ts.map +1 -1
- package/lib/connectionStateHandler.js +25 -2
- package/lib/connectionStateHandler.js.map +1 -1
- package/lib/container.d.ts +74 -44
- package/lib/container.d.ts.map +1 -1
- package/lib/container.js +82 -112
- package/lib/container.js.map +1 -1
- package/lib/containerContext.d.ts +2 -2
- package/lib/containerContext.d.ts.map +1 -1
- package/lib/containerContext.js +3 -7
- package/lib/containerContext.js.map +1 -1
- package/lib/containerStorageAdapter.d.ts +3 -3
- package/lib/containerStorageAdapter.d.ts.map +1 -1
- package/lib/containerStorageAdapter.js +6 -15
- package/lib/containerStorageAdapter.js.map +1 -1
- package/lib/contracts.d.ts +8 -0
- package/lib/contracts.d.ts.map +1 -1
- package/lib/contracts.js.map +1 -1
- package/lib/deltaManager.d.ts +21 -9
- package/lib/deltaManager.d.ts.map +1 -1
- package/lib/deltaManager.js +44 -33
- package/lib/deltaManager.js.map +1 -1
- package/lib/deltaQueue.d.ts +2 -3
- package/lib/deltaQueue.d.ts.map +1 -1
- package/lib/deltaQueue.js +2 -3
- package/lib/deltaQueue.js.map +1 -1
- package/lib/index.d.ts +1 -2
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +1 -1
- package/lib/index.js.map +1 -1
- package/lib/loader.d.ts +9 -7
- package/lib/loader.d.ts.map +1 -1
- package/lib/loader.js +47 -61
- 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/retriableDocumentStorageService.d.ts +3 -2
- package/lib/retriableDocumentStorageService.d.ts.map +1 -1
- package/lib/retriableDocumentStorageService.js.map +1 -1
- package/lib/utils.d.ts +2 -0
- package/lib/utils.d.ts.map +1 -1
- package/lib/utils.js +7 -1
- package/lib/utils.js.map +1 -1
- package/package.json +16 -18
- package/src/connectionManager.ts +40 -22
- package/src/connectionStateHandler.ts +52 -8
- package/src/container.ts +191 -159
- package/src/containerContext.ts +3 -9
- package/src/containerStorageAdapter.ts +8 -20
- package/src/contracts.ts +10 -0
- package/src/deltaManager.ts +59 -37
- package/src/deltaQueue.ts +2 -3
- package/src/index.ts +1 -8
- package/src/loader.ts +85 -83
- package/src/packageVersion.ts +1 -1
- package/src/retriableDocumentStorageService.ts +3 -2
- package/src/utils.ts +15 -1
package/dist/container.js
CHANGED
|
@@ -127,26 +127,18 @@ async function ReportIfTooLong(logger, eventName, action) {
|
|
|
127
127
|
}
|
|
128
128
|
exports.ReportIfTooLong = ReportIfTooLong;
|
|
129
129
|
const summarizerClientType = "summarizer";
|
|
130
|
-
/**
|
|
131
|
-
* @deprecated - In the next release Container will no longer be exported, IContainer should be used in its place.
|
|
132
|
-
*/
|
|
133
130
|
class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
134
131
|
/**
|
|
135
132
|
* @internal
|
|
136
133
|
*/
|
|
137
|
-
constructor(
|
|
138
|
-
var _a
|
|
134
|
+
constructor(createProps, loadProps) {
|
|
135
|
+
var _a;
|
|
139
136
|
super((name, error) => {
|
|
140
137
|
this.mc.logger.sendErrorEvent({
|
|
141
138
|
eventName: "ContainerEventHandlerException",
|
|
142
139
|
name: typeof name === "string" ? name : undefined,
|
|
143
140
|
}, error);
|
|
144
141
|
});
|
|
145
|
-
this.loader = loader;
|
|
146
|
-
this.protocolHandlerBuilder = protocolHandlerBuilder;
|
|
147
|
-
// Tells if container can reconnect on losing fist connection
|
|
148
|
-
// If false, container gets closed on loss of connection.
|
|
149
|
-
this._canReconnect = true;
|
|
150
142
|
/**
|
|
151
143
|
* Lifecycle state of the container, used mainly to prevent re-entrancy and telemetry
|
|
152
144
|
*
|
|
@@ -174,26 +166,41 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
174
166
|
this.savedOps = [];
|
|
175
167
|
this.setAutoReconnectTime = common_utils_1.performance.now();
|
|
176
168
|
this._disposed = false;
|
|
177
|
-
|
|
178
|
-
this.
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
169
|
+
const { canReconnect, clientDetailsOverride, urlResolver, documentServiceFactory, codeLoader, options, scope, subLogger, detachedBlobStorage, protocolHandlerBuilder, } = createProps;
|
|
170
|
+
this.connectionTransitionTimes[connectionState_1.ConnectionState.Disconnected] = common_utils_1.performance.now();
|
|
171
|
+
const pendingLocalState = loadProps === null || loadProps === void 0 ? void 0 : loadProps.pendingLocalState;
|
|
172
|
+
this._canReconnect = canReconnect !== null && canReconnect !== void 0 ? canReconnect : true;
|
|
173
|
+
this.clientDetailsOverride = clientDetailsOverride;
|
|
174
|
+
this.urlResolver = urlResolver;
|
|
175
|
+
this.serviceFactory = documentServiceFactory;
|
|
176
|
+
this.codeLoader = codeLoader;
|
|
177
|
+
// Warning: this is only a shallow clone. Mutation of any individual loader option will mutate it for
|
|
178
|
+
// all clients that were loaded from the same loader (including summarizer clients).
|
|
179
|
+
// Tracking alternative ways to handle this in AB#4129.
|
|
180
|
+
this.options = Object.assign({}, options);
|
|
181
|
+
this.scope = scope;
|
|
182
|
+
this.detachedBlobStorage = detachedBlobStorage;
|
|
183
|
+
this.protocolHandlerBuilder =
|
|
184
|
+
protocolHandlerBuilder !== null && protocolHandlerBuilder !== void 0 ? protocolHandlerBuilder : ((...args) => new protocol_1.ProtocolHandler(...args, new audience_1.Audience()));
|
|
185
|
+
// Note that we capture the createProps here so we can replicate the creation call when we want to clone.
|
|
186
|
+
this.clone = async (_loadProps, createParamOverrides) => {
|
|
187
|
+
return Container.load(_loadProps, Object.assign(Object.assign({}, createProps), createParamOverrides));
|
|
188
|
+
};
|
|
182
189
|
// Create logger for data stores to use
|
|
183
190
|
const type = this.client.details.type;
|
|
184
191
|
const interactive = this.client.details.capabilities.interactive;
|
|
185
192
|
const clientType = `${interactive ? "interactive" : "noninteractive"}${type !== undefined && type !== "" ? `/${type}` : ""}`;
|
|
186
193
|
// Need to use the property getter for docId because for detached flow we don't have the docId initially.
|
|
187
194
|
// We assign the id later so property getter is used.
|
|
188
|
-
this.subLogger = telemetry_utils_1.ChildLogger.create(
|
|
195
|
+
this.subLogger = telemetry_utils_1.ChildLogger.create(subLogger, undefined, {
|
|
189
196
|
all: {
|
|
190
197
|
clientType,
|
|
191
198
|
containerId: (0, uuid_1.v4)(),
|
|
192
|
-
docId: () => { var _a
|
|
199
|
+
docId: () => { var _a; return (_a = this.resolvedUrl) === null || _a === void 0 ? void 0 : _a.id; },
|
|
193
200
|
containerAttachState: () => this._attachState,
|
|
194
201
|
containerLifecycleState: () => this._lifecycleState,
|
|
195
202
|
containerConnectionState: () => connectionState_1.ConnectionState[this.connectionState],
|
|
196
|
-
serializedContainer:
|
|
203
|
+
serializedContainer: pendingLocalState !== undefined,
|
|
197
204
|
},
|
|
198
205
|
// we need to be judicious with our logging here to avoid generating too much data
|
|
199
206
|
// all data logged here should be broadly applicable, and not specific to a
|
|
@@ -216,10 +223,6 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
216
223
|
});
|
|
217
224
|
// Prefix all events in this file with container-loader
|
|
218
225
|
this.mc = (0, telemetry_utils_1.loggerToMonitoringContext)(telemetry_utils_1.ChildLogger.create(this.subLogger, "Container"));
|
|
219
|
-
// Warning: this is only a shallow clone. Mutation of any individual loader option will mutate it for
|
|
220
|
-
// all clients that were loaded from the same loader (including summarizer clients).
|
|
221
|
-
// Tracking alternative ways to handle this in AB#4129.
|
|
222
|
-
this.options = Object.assign({}, this.loader.services.options);
|
|
223
226
|
this._deltaManager = this.createDeltaManager();
|
|
224
227
|
this.connectionStateHandler = (0, connectionStateHandler_1.createConnectionStateHandler)({
|
|
225
228
|
logger: this.mc.logger,
|
|
@@ -235,7 +238,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
235
238
|
}
|
|
236
239
|
},
|
|
237
240
|
shouldClientJoinWrite: () => this._deltaManager.connectionManager.shouldJoinWrite(),
|
|
238
|
-
maxClientLeaveWaitTime:
|
|
241
|
+
maxClientLeaveWaitTime: options.maxClientLeaveWaitTime,
|
|
239
242
|
logConnectionIssue: (eventName, category, details) => {
|
|
240
243
|
const mode = this.connectionMode;
|
|
241
244
|
// We get here when socket does not receive any ops on "write" connection, including
|
|
@@ -259,7 +262,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
259
262
|
this.connect();
|
|
260
263
|
}
|
|
261
264
|
},
|
|
262
|
-
}, this.deltaManager,
|
|
265
|
+
}, this.deltaManager, pendingLocalState === null || pendingLocalState === void 0 ? void 0 : pendingLocalState.clientId);
|
|
263
266
|
this.on(savedContainerEvent, () => {
|
|
264
267
|
this.connectionStateHandler.containerSaved();
|
|
265
268
|
});
|
|
@@ -271,8 +274,8 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
271
274
|
: (0, driver_utils_1.combineAppAndProtocolSummary)(summaryTree, this.captureProtocolSummary());
|
|
272
275
|
// Whether the combined summary tree has been forced on by either the loader option or the monitoring context.
|
|
273
276
|
// Even if not forced on via this flag, combined summaries may still be enabled by service policy.
|
|
274
|
-
const forceEnableSummarizeProtocolTree = (
|
|
275
|
-
this.storageAdapter = new containerStorageAdapter_1.ContainerStorageAdapter(
|
|
277
|
+
const forceEnableSummarizeProtocolTree = (_a = this.mc.config.getBoolean("Fluid.Container.summarizeProtocolTree2")) !== null && _a !== void 0 ? _a : options.summarizeProtocolTree;
|
|
278
|
+
this.storageAdapter = new containerStorageAdapter_1.ContainerStorageAdapter(detachedBlobStorage, this.mc.logger, pendingLocalState === null || pendingLocalState === void 0 ? void 0 : pendingLocalState.snapshotBlobs, addProtocolSummaryIfMissing, forceEnableSummarizeProtocolTree);
|
|
276
279
|
const isDomAvailable = typeof document === "object" &&
|
|
277
280
|
document !== null &&
|
|
278
281
|
typeof document.addEventListener === "function" &&
|
|
@@ -298,33 +301,28 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
298
301
|
* Load an existing container.
|
|
299
302
|
* @internal
|
|
300
303
|
*/
|
|
301
|
-
static async load(
|
|
302
|
-
const
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
canReconnect: loadOptions.canReconnect,
|
|
306
|
-
serializedContainerState: pendingLocalState,
|
|
307
|
-
}, protocolHandlerBuilder);
|
|
304
|
+
static async load(loadProps, createProps) {
|
|
305
|
+
const { version, pendingLocalState, loadMode, resolvedUrl } = loadProps;
|
|
306
|
+
const container = new Container(createProps, loadProps);
|
|
307
|
+
const disableRecordHeapSize = container.mc.config.getBoolean("Fluid.Loader.DisableRecordHeapSize");
|
|
308
308
|
return telemetry_utils_1.PerformanceEvent.timedExecAsync(container.mc.logger, { eventName: "Load" }, async (event) => new Promise((resolve, reject) => {
|
|
309
|
-
var _a, _b;
|
|
310
|
-
const version = loadOptions.version;
|
|
311
309
|
const defaultMode = { opsBeforeReturn: "cached" };
|
|
312
310
|
// if we have pendingLocalState, anything we cached is not useful and we shouldn't wait for connection
|
|
313
311
|
// to return container, so ignore this value and use undefined for opsBeforeReturn
|
|
314
312
|
const mode = pendingLocalState
|
|
315
|
-
? Object.assign(Object.assign({}, (
|
|
313
|
+
? Object.assign(Object.assign({}, (loadMode !== null && loadMode !== void 0 ? loadMode : defaultMode)), { opsBeforeReturn: undefined }) : loadMode !== null && loadMode !== void 0 ? loadMode : defaultMode;
|
|
316
314
|
const onClosed = (err) => {
|
|
317
315
|
// pre-0.58 error message: containerClosedWithoutErrorDuringLoad
|
|
318
316
|
reject(err !== null && err !== void 0 ? err : new container_utils_1.GenericError("Container closed without error during load"));
|
|
319
317
|
};
|
|
320
318
|
container.on("closed", onClosed);
|
|
321
319
|
container
|
|
322
|
-
.load(version, mode, pendingLocalState)
|
|
320
|
+
.load(version, mode, resolvedUrl, pendingLocalState)
|
|
323
321
|
.finally(() => {
|
|
324
322
|
container.removeListener("closed", onClosed);
|
|
325
323
|
})
|
|
326
324
|
.then((props) => {
|
|
327
|
-
event.end(Object.assign(Object.assign({}, props),
|
|
325
|
+
event.end(Object.assign(Object.assign({}, props), loadMode));
|
|
328
326
|
resolve(container);
|
|
329
327
|
}, (error) => {
|
|
330
328
|
const err = (0, telemetry_utils_1.normalizeError)(error);
|
|
@@ -334,13 +332,13 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
334
332
|
container.close(err);
|
|
335
333
|
onClosed(err);
|
|
336
334
|
});
|
|
337
|
-
}), { start: true, end: true, cancel: "generic" });
|
|
335
|
+
}), { start: true, end: true, cancel: "generic" }, disableRecordHeapSize !== true /* recordHeapSize */);
|
|
338
336
|
}
|
|
339
337
|
/**
|
|
340
338
|
* Create a new container in a detached state.
|
|
341
339
|
*/
|
|
342
|
-
static async createDetached(
|
|
343
|
-
const container = new Container(
|
|
340
|
+
static async createDetached(createProps, codeDetails) {
|
|
341
|
+
const container = new Container(createProps);
|
|
344
342
|
return telemetry_utils_1.PerformanceEvent.timedExecAsync(container.mc.logger, { eventName: "CreateDetached" }, async (_event) => {
|
|
345
343
|
await container.createDetached(codeDetails);
|
|
346
344
|
return container;
|
|
@@ -350,8 +348,8 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
350
348
|
* Create a new container in a detached state that is initialized with a
|
|
351
349
|
* snapshot from a previous detached container.
|
|
352
350
|
*/
|
|
353
|
-
static async rehydrateDetachedFromSnapshot(
|
|
354
|
-
const container = new Container(
|
|
351
|
+
static async rehydrateDetachedFromSnapshot(createProps, snapshot) {
|
|
352
|
+
const container = new Container(createProps);
|
|
355
353
|
return telemetry_utils_1.PerformanceEvent.timedExecAsync(container.mc.logger, { eventName: "RehydrateDetachedFromSnapshot" }, async (_event) => {
|
|
356
354
|
const deserializedSummary = JSON.parse(snapshot);
|
|
357
355
|
await container.rehydrateDetachedFromSnapshot(deserializedSummary);
|
|
@@ -395,7 +393,19 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
395
393
|
return this;
|
|
396
394
|
}
|
|
397
395
|
get resolvedUrl() {
|
|
398
|
-
|
|
396
|
+
var _a;
|
|
397
|
+
/**
|
|
398
|
+
* All attached containers will have a document service,
|
|
399
|
+
* this is required, as attached containers are attached to
|
|
400
|
+
* a service. Detached containers will neither have a document
|
|
401
|
+
* service or a resolved url as they only exist locally.
|
|
402
|
+
* in order to create a document service a resolved url must
|
|
403
|
+
* first be obtained, this is how the container is identified.
|
|
404
|
+
* Because of this, the document service's resolved url
|
|
405
|
+
* is always the same as the containers, as we had to
|
|
406
|
+
* obtain the resolved url, and then create the service from it.
|
|
407
|
+
*/
|
|
408
|
+
return (_a = this.service) === null || _a === void 0 ? void 0 : _a.resolvedUrl;
|
|
399
409
|
}
|
|
400
410
|
get loadedFromVersion() {
|
|
401
411
|
return this._loadedFromVersion;
|
|
@@ -481,18 +491,6 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
481
491
|
get isDirty() {
|
|
482
492
|
return this._dirtyContainer;
|
|
483
493
|
}
|
|
484
|
-
get serviceFactory() {
|
|
485
|
-
return this.loader.services.documentServiceFactory;
|
|
486
|
-
}
|
|
487
|
-
get urlResolver() {
|
|
488
|
-
return this.loader.services.urlResolver;
|
|
489
|
-
}
|
|
490
|
-
get scope() {
|
|
491
|
-
return this.loader.services.scope;
|
|
492
|
-
}
|
|
493
|
-
get codeLoader() {
|
|
494
|
-
return this.loader.services.codeLoader;
|
|
495
|
-
}
|
|
496
494
|
/**
|
|
497
495
|
* {@inheritDoc @fluidframework/container-definitions#IContainer.entryPoint}
|
|
498
496
|
*/
|
|
@@ -532,7 +530,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
532
530
|
return this.protocolHandler.quorum;
|
|
533
531
|
}
|
|
534
532
|
dispose(error) {
|
|
535
|
-
this._deltaManager.
|
|
533
|
+
this._deltaManager.dispose(error);
|
|
536
534
|
this.verifyClosed();
|
|
537
535
|
}
|
|
538
536
|
close(error) {
|
|
@@ -548,7 +546,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
548
546
|
(0, common_utils_1.assert)(this._lifecycleState === "closed" || this._lifecycleState === "disposed", 0x314 /* Container properly closed */);
|
|
549
547
|
}
|
|
550
548
|
closeCore(error) {
|
|
551
|
-
var _a
|
|
549
|
+
var _a;
|
|
552
550
|
(0, common_utils_1.assert)(!this.closed, 0x315 /* re-entrancy */);
|
|
553
551
|
try {
|
|
554
552
|
// Ensure that we raise all key events even if one of these throws
|
|
@@ -566,12 +564,6 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
566
564
|
this._lifecycleState = "closing";
|
|
567
565
|
(_a = this._protocolHandler) === null || _a === void 0 ? void 0 : _a.close();
|
|
568
566
|
this.connectionStateHandler.dispose();
|
|
569
|
-
(_b = this._context) === null || _b === void 0 ? void 0 : _b.dispose(error !== undefined ? new Error(error.message) : undefined);
|
|
570
|
-
this.storageAdapter.dispose();
|
|
571
|
-
// Notify storage about critical errors. They may be due to disconnect between client & server knowledge
|
|
572
|
-
// about file, like file being overwritten in storage, but client having stale local cache.
|
|
573
|
-
// Driver need to ensure all caches are cleared on critical errors
|
|
574
|
-
(_c = this.service) === null || _c === void 0 ? void 0 : _c.dispose(error);
|
|
575
567
|
}
|
|
576
568
|
catch (exception) {
|
|
577
569
|
this.mc.logger.sendErrorEvent({ eventName: "ContainerCloseException" }, exception);
|
|
@@ -660,8 +652,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
660
652
|
const appSummary = this.context.createSummary();
|
|
661
653
|
const protocolSummary = this.captureProtocolSummary();
|
|
662
654
|
const combinedSummary = (0, driver_utils_1.combineAppAndProtocolSummary)(appSummary, protocolSummary);
|
|
663
|
-
if (this.
|
|
664
|
-
this.loader.services.detachedBlobStorage.size > 0) {
|
|
655
|
+
if (this.detachedBlobStorage && this.detachedBlobStorage.size > 0) {
|
|
665
656
|
combinedSummary.tree[".hasAttachmentBlobs"] = {
|
|
666
657
|
type: protocol_definitions_1.SummaryType.Blob,
|
|
667
658
|
content: "true",
|
|
@@ -680,8 +671,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
680
671
|
(0, common_utils_1.assert)(this._attachState === container_definitions_1.AttachState.Detached && !this.attachStarted, 0x205 /* "attach() called more than once" */);
|
|
681
672
|
this.attachStarted = true;
|
|
682
673
|
// If attachment blobs were uploaded in detached state we will go through a different attach flow
|
|
683
|
-
const hasAttachmentBlobs = this.
|
|
684
|
-
this.loader.services.detachedBlobStorage.size > 0;
|
|
674
|
+
const hasAttachmentBlobs = this.detachedBlobStorage !== undefined && this.detachedBlobStorage.size > 0;
|
|
685
675
|
try {
|
|
686
676
|
(0, common_utils_1.assert)(this.deltaManager.inbound.length === 0, 0x0d6 /* "Inbound queue should be empty when attaching" */);
|
|
687
677
|
let summary;
|
|
@@ -705,31 +695,28 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
705
695
|
}
|
|
706
696
|
}
|
|
707
697
|
// Actually go and create the resolved document
|
|
708
|
-
const createNewResolvedUrl = await this.urlResolver.resolve(request);
|
|
709
|
-
(0, driver_utils_1.ensureFluidResolvedUrl)(createNewResolvedUrl);
|
|
710
698
|
if (this.service === undefined) {
|
|
711
|
-
|
|
699
|
+
const createNewResolvedUrl = await this.urlResolver.resolve(request);
|
|
700
|
+
(0, common_utils_1.assert)(this.client.details.type !== summarizerClientType &&
|
|
701
|
+
createNewResolvedUrl !== undefined, 0x2c4 /* "client should not be summarizer before container is created" */);
|
|
712
702
|
this.service = await (0, driver_utils_1.runWithRetry)(async () => this.serviceFactory.createContainer(summary, createNewResolvedUrl, this.subLogger, false), "containerAttach", this.mc.logger, {
|
|
713
703
|
cancel: this.closeSignal,
|
|
714
704
|
});
|
|
715
705
|
}
|
|
716
|
-
const resolvedUrl = this.service.resolvedUrl;
|
|
717
|
-
(0, driver_utils_1.ensureFluidResolvedUrl)(resolvedUrl);
|
|
718
|
-
this._resolvedUrl = resolvedUrl;
|
|
719
706
|
await this.storageAdapter.connectToService(this.service);
|
|
720
707
|
if (hasAttachmentBlobs) {
|
|
721
708
|
// upload blobs to storage
|
|
722
|
-
(0, common_utils_1.assert)(!!this.
|
|
709
|
+
(0, common_utils_1.assert)(!!this.detachedBlobStorage, 0x24e /* "assertion for type narrowing" */);
|
|
723
710
|
// build a table mapping IDs assigned locally to IDs assigned by storage and pass it to runtime to
|
|
724
711
|
// support blob handles that only know about the local IDs
|
|
725
712
|
const redirectTable = new Map();
|
|
726
713
|
// if new blobs are added while uploading, upload them too
|
|
727
|
-
while (redirectTable.size < this.
|
|
728
|
-
const newIds = this.
|
|
714
|
+
while (redirectTable.size < this.detachedBlobStorage.size) {
|
|
715
|
+
const newIds = this.detachedBlobStorage
|
|
729
716
|
.getBlobIds()
|
|
730
717
|
.filter((id) => !redirectTable.has(id));
|
|
731
718
|
for (const id of newIds) {
|
|
732
|
-
const blob = await this.
|
|
719
|
+
const blob = await this.detachedBlobStorage.readBlob(id);
|
|
733
720
|
const response = await this.storageAdapter.createBlob(blob);
|
|
734
721
|
redirectTable.set(id, response.id);
|
|
735
722
|
}
|
|
@@ -764,12 +751,8 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
764
751
|
catch (error) {
|
|
765
752
|
// add resolved URL on error object so that host has the ability to find this document and delete it
|
|
766
753
|
const newError = (0, telemetry_utils_1.normalizeError)(error);
|
|
767
|
-
|
|
768
|
-
if ((0, driver_utils_1.isFluidResolvedUrl)(resolvedUrl)) {
|
|
769
|
-
newError.addTelemetryProperties({ resolvedUrl: resolvedUrl.url });
|
|
770
|
-
}
|
|
754
|
+
newError.addTelemetryProperties({ resolvedUrl: (_a = this.resolvedUrl) === null || _a === void 0 ? void 0 : _a.url });
|
|
771
755
|
this.close(newError);
|
|
772
|
-
(_a = this.dispose) === null || _a === void 0 ? void 0 : _a.call(this, newError);
|
|
773
756
|
throw newError;
|
|
774
757
|
}
|
|
775
758
|
}, { start: true, end: true, cancel: "generic" });
|
|
@@ -864,7 +847,6 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
864
847
|
.catch(() => false);
|
|
865
848
|
}
|
|
866
849
|
async processCodeProposal() {
|
|
867
|
-
var _a;
|
|
868
850
|
const codeDetails = this.getCodeDetailsFromQuorum();
|
|
869
851
|
await Promise.all([
|
|
870
852
|
this.deltaManager.inbound.pause(),
|
|
@@ -878,19 +860,12 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
878
860
|
// pre-0.58 error message: existingContextDoesNotSatisfyIncomingProposal
|
|
879
861
|
const error = new container_utils_1.GenericError("Existing context does not satisfy incoming proposal");
|
|
880
862
|
this.close(error);
|
|
881
|
-
(_a = this.dispose) === null || _a === void 0 ? void 0 : _a.call(this, error);
|
|
882
863
|
}
|
|
883
864
|
async getVersion(version) {
|
|
884
865
|
const versions = await this.storageAdapter.getVersions(version, 1);
|
|
885
866
|
return versions[0];
|
|
886
867
|
}
|
|
887
|
-
recordConnectStartTime() {
|
|
888
|
-
if (this.connectionTransitionTimes[connectionState_1.ConnectionState.Disconnected] === undefined) {
|
|
889
|
-
this.connectionTransitionTimes[connectionState_1.ConnectionState.Disconnected] = common_utils_1.performance.now();
|
|
890
|
-
}
|
|
891
|
-
}
|
|
892
868
|
connectToDeltaStream(args) {
|
|
893
|
-
this.recordConnectStartTime();
|
|
894
869
|
// All agents need "write" access, including summarizer.
|
|
895
870
|
if (!this._canReconnect || !this.client.details.capabilities.interactive) {
|
|
896
871
|
args.mode = "write";
|
|
@@ -902,12 +877,9 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
902
877
|
*
|
|
903
878
|
* @param specifiedVersion - Version SHA to load snapshot. If not specified, will fetch the latest snapshot.
|
|
904
879
|
*/
|
|
905
|
-
async load(specifiedVersion, loadMode, pendingLocalState) {
|
|
880
|
+
async load(specifiedVersion, loadMode, resolvedUrl, pendingLocalState) {
|
|
906
881
|
var _a;
|
|
907
|
-
|
|
908
|
-
throw new Error("Attempting to load without a resolved url");
|
|
909
|
-
}
|
|
910
|
-
this.service = await this.serviceFactory.createDocumentService(this._resolvedUrl, this.subLogger, this.client.details.type === summarizerClientType);
|
|
882
|
+
this.service = await this.serviceFactory.createDocumentService(resolvedUrl, this.subLogger, this.client.details.type === summarizerClientType);
|
|
911
883
|
// Ideally we always connect as "read" by default.
|
|
912
884
|
// Currently that works with SPO & r11s, because we get "write" connection when connecting to non-existing file.
|
|
913
885
|
// We should not rely on it by (one of them will address the issue, but we need to address both)
|
|
@@ -933,9 +905,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
933
905
|
else {
|
|
934
906
|
// if we have pendingLocalState we can load without storage; don't wait for connection
|
|
935
907
|
this.storageAdapter.connectToService(this.service).catch((error) => {
|
|
936
|
-
var _a;
|
|
937
908
|
this.close(error);
|
|
938
|
-
(_a = this.dispose) === null || _a === void 0 ? void 0 : _a.call(this, error);
|
|
939
909
|
});
|
|
940
910
|
}
|
|
941
911
|
this._attachState = container_definitions_1.AttachState.Attached;
|
|
@@ -1061,8 +1031,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
1061
1031
|
}
|
|
1062
1032
|
async rehydrateDetachedFromSnapshot(detachedContainerSnapshot) {
|
|
1063
1033
|
if (detachedContainerSnapshot.tree[".hasAttachmentBlobs"] !== undefined) {
|
|
1064
|
-
(0, common_utils_1.assert)(!!this.
|
|
1065
|
-
this.loader.services.detachedBlobStorage.size > 0, 0x250 /* "serialized container with attachment blobs must be rehydrated with detached blob storage" */);
|
|
1034
|
+
(0, common_utils_1.assert)(!!this.detachedBlobStorage && this.detachedBlobStorage.size > 0, 0x250 /* "serialized container with attachment blobs must be rehydrated with detached blob storage" */);
|
|
1066
1035
|
delete detachedContainerSnapshot.tree[".hasAttachmentBlobs"];
|
|
1067
1036
|
}
|
|
1068
1037
|
const snapshotTree = (0, utils_1.getSnapshotTreeFromSerializedContainer)(detachedContainerSnapshot);
|
|
@@ -1115,9 +1084,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
1115
1084
|
this.initializeProtocolState(attributes, quorumSnapshot);
|
|
1116
1085
|
}
|
|
1117
1086
|
initializeProtocolState(attributes, quorumSnapshot) {
|
|
1118
|
-
|
|
1119
|
-
const protocolHandlerBuilder = (_a = this.protocolHandlerBuilder) !== null && _a !== void 0 ? _a : ((...args) => new protocol_1.ProtocolHandler(...args, new audience_1.Audience()));
|
|
1120
|
-
const protocol = protocolHandlerBuilder(attributes, quorumSnapshot, (key, value) => this.submitMessage(protocol_definitions_1.MessageType.Propose, JSON.stringify({ key, value })));
|
|
1087
|
+
const protocol = this.protocolHandlerBuilder(attributes, quorumSnapshot, (key, value) => this.submitMessage(protocol_definitions_1.MessageType.Propose, JSON.stringify({ key, value })));
|
|
1121
1088
|
const protocolLogger = telemetry_utils_1.ChildLogger.create(this.subLogger, "ProtocolHandler");
|
|
1122
1089
|
protocol.quorum.on("error", (error) => {
|
|
1123
1090
|
protocolLogger.sendErrorEvent(error);
|
|
@@ -1137,10 +1104,8 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
1137
1104
|
});
|
|
1138
1105
|
}
|
|
1139
1106
|
this.processCodeProposal().catch((error) => {
|
|
1140
|
-
var _a;
|
|
1141
1107
|
const normalizedError = (0, telemetry_utils_1.normalizeError)(error);
|
|
1142
1108
|
this.close(normalizedError);
|
|
1143
|
-
(_a = this.dispose) === null || _a === void 0 ? void 0 : _a.call(this, normalizedError);
|
|
1144
1109
|
throw error;
|
|
1145
1110
|
});
|
|
1146
1111
|
}
|
|
@@ -1224,6 +1189,12 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
1224
1189
|
(0, common_utils_1.assert)(this.connectionMode === details.mode, 0x4b7 /* mismatch */);
|
|
1225
1190
|
this.connectionStateHandler.receivedConnectEvent(details);
|
|
1226
1191
|
});
|
|
1192
|
+
deltaManager.on("establishingConnection", (reason) => {
|
|
1193
|
+
this.connectionStateHandler.establishingConnection(reason);
|
|
1194
|
+
});
|
|
1195
|
+
deltaManager.on("cancelEstablishingConnection", (reason) => {
|
|
1196
|
+
this.connectionStateHandler.cancelEstablishingConnection(reason);
|
|
1197
|
+
});
|
|
1227
1198
|
deltaManager.on("disconnect", (reason, error) => {
|
|
1228
1199
|
var _a;
|
|
1229
1200
|
(_a = this.collabWindowTracker) === null || _a === void 0 ? void 0 : _a.stopSequenceNumberUpdate();
|
|
@@ -1280,8 +1251,8 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
1280
1251
|
time - this.connectionTransitionTimes[connectionState_1.ConnectionState.Disconnected];
|
|
1281
1252
|
durationFromDisconnected = telemetry_utils_1.TelemetryLogger.formatTick(durationFromDisconnected);
|
|
1282
1253
|
}
|
|
1283
|
-
else {
|
|
1284
|
-
// This info is of most
|
|
1254
|
+
else if (value === connectionState_1.ConnectionState.CatchingUp) {
|
|
1255
|
+
// This info is of most interesting while Catching Up.
|
|
1285
1256
|
checkpointSequenceNumber = this.deltaManager.lastKnownSeqNumber;
|
|
1286
1257
|
if (this.deltaManager.hasCheckpointSequenceNumber) {
|
|
1287
1258
|
opsBehind = checkpointSequenceNumber - this.deltaManager.lastSequenceNumber;
|
|
@@ -1330,7 +1301,6 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
1330
1301
|
}
|
|
1331
1302
|
// back-compat: ADO #1385: Remove in the future, summary op should come through submitSummaryMessage()
|
|
1332
1303
|
submitContainerMessage(type, contents, batch, metadata) {
|
|
1333
|
-
var _a;
|
|
1334
1304
|
switch (type) {
|
|
1335
1305
|
case protocol_definitions_1.MessageType.Operation:
|
|
1336
1306
|
return this.submitMessage(type, JSON.stringify(contents), batch, metadata);
|
|
@@ -1339,7 +1309,6 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
1339
1309
|
default: {
|
|
1340
1310
|
const newError = new container_utils_1.GenericError("invalidContainerSubmitOpType", undefined /* error */, { messageType: type });
|
|
1341
1311
|
this.close(newError);
|
|
1342
|
-
(_a = this.dispose) === null || _a === void 0 ? void 0 : _a.call(this, newError);
|
|
1343
1312
|
return -1;
|
|
1344
1313
|
}
|
|
1345
1314
|
}
|
|
@@ -1448,8 +1417,9 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
1448
1417
|
(0, common_utils_1.assert)(((_a = this._context) === null || _a === void 0 ? void 0 : _a.disposed) !== false, 0x0dd /* "Existing context not disposed" */);
|
|
1449
1418
|
// The relative loader will proxy requests to '/' to the loader itself assuming no non-cache flags
|
|
1450
1419
|
// are set. Global requests will still go directly to the loader
|
|
1451
|
-
const
|
|
1452
|
-
|
|
1420
|
+
const maybeLoader = this.scope;
|
|
1421
|
+
const loader = new loader_1.RelativeLoader(this, maybeLoader.ILoader);
|
|
1422
|
+
this._context = await containerContext_1.ContainerContext.createOrLoad(this, this.scope, this.codeLoader, codeDetails, snapshot, new deltaManagerProxy_1.DeltaManagerProxy(this._deltaManager), new quorum_1.QuorumProxy(this.protocolHandler.quorum), 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), Container.version, (dirty) => this.updateDirtyContainerState(dirty), existing, pendingLocalState);
|
|
1453
1423
|
this.emit("contextChanged", codeDetails);
|
|
1454
1424
|
}
|
|
1455
1425
|
updateDirtyContainerState(dirty) {
|