@fluidframework/container-loader 2.0.0-internal.4.3.0 → 2.0.0-internal.5.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 +28 -0
- package/README.md +6 -3
- package/dist/connectionManager.d.ts +5 -3
- package/dist/connectionManager.d.ts.map +1 -1
- package/dist/connectionManager.js +19 -15
- package/dist/connectionManager.js.map +1 -1
- package/dist/connectionStateHandler.d.ts +11 -9
- package/dist/connectionStateHandler.d.ts.map +1 -1
- package/dist/connectionStateHandler.js +11 -11
- package/dist/connectionStateHandler.js.map +1 -1
- package/dist/container.d.ts +62 -36
- package/dist/container.d.ts.map +1 -1
- package/dist/container.js +71 -89
- 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.map +1 -1
- package/dist/contracts.d.ts +3 -3
- package/dist/contracts.d.ts.map +1 -1
- package/dist/contracts.js.map +1 -1
- package/dist/deltaManager.d.ts +3 -2
- package/dist/deltaManager.d.ts.map +1 -1
- package/dist/deltaManager.js +4 -5
- package/dist/deltaManager.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 -5
- package/dist/loader.d.ts.map +1 -1
- package/dist/loader.js +28 -34
- 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/lib/connectionManager.d.ts +5 -3
- package/lib/connectionManager.d.ts.map +1 -1
- package/lib/connectionManager.js +20 -16
- package/lib/connectionManager.js.map +1 -1
- package/lib/connectionStateHandler.d.ts +11 -9
- package/lib/connectionStateHandler.d.ts.map +1 -1
- package/lib/connectionStateHandler.js +12 -12
- package/lib/connectionStateHandler.js.map +1 -1
- package/lib/container.d.ts +62 -36
- package/lib/container.d.ts.map +1 -1
- package/lib/container.js +72 -90
- 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.map +1 -1
- package/lib/contracts.d.ts +3 -3
- package/lib/contracts.d.ts.map +1 -1
- package/lib/contracts.js.map +1 -1
- package/lib/deltaManager.d.ts +3 -2
- package/lib/deltaManager.d.ts.map +1 -1
- package/lib/deltaManager.js +5 -6
- package/lib/deltaManager.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 -5
- package/lib/loader.d.ts.map +1 -1
- package/lib/loader.js +28 -34
- 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/package.json +27 -10
- package/src/connectionManager.ts +29 -20
- package/src/connectionStateHandler.ts +26 -17
- package/src/container.ts +169 -147
- package/src/containerContext.ts +3 -9
- package/src/containerStorageAdapter.ts +4 -4
- package/src/contracts.ts +3 -3
- package/src/deltaManager.ts +13 -8
- package/src/index.ts +1 -8
- package/src/loader.ts +56 -47
- package/src/packageVersion.ts +1 -1
- package/src/retriableDocumentStorageService.ts +3 -2
package/src/container.ts
CHANGED
|
@@ -7,11 +7,7 @@
|
|
|
7
7
|
import merge from "lodash/merge";
|
|
8
8
|
|
|
9
9
|
import { v4 as uuid } from "uuid";
|
|
10
|
-
import {
|
|
11
|
-
ITelemetryLogger,
|
|
12
|
-
ITelemetryProperties,
|
|
13
|
-
TelemetryEventCategory,
|
|
14
|
-
} from "@fluidframework/common-definitions";
|
|
10
|
+
import { ITelemetryProperties, TelemetryEventCategory } from "@fluidframework/common-definitions";
|
|
15
11
|
import { assert, performance, unreachableCase } from "@fluidframework/common-utils";
|
|
16
12
|
import { IRequest, IResponse, IFluidRouter, FluidObject } from "@fluidframework/core-interfaces";
|
|
17
13
|
import {
|
|
@@ -29,22 +25,24 @@ import {
|
|
|
29
25
|
IFluidCodeDetails,
|
|
30
26
|
isFluidCodeDetails,
|
|
31
27
|
IBatchMessage,
|
|
28
|
+
ICodeDetailsLoader,
|
|
29
|
+
IHostLoader,
|
|
32
30
|
} from "@fluidframework/container-definitions";
|
|
33
31
|
import { GenericError, UsageError } from "@fluidframework/container-utils";
|
|
34
32
|
import {
|
|
33
|
+
IAnyDriverError,
|
|
35
34
|
IDocumentService,
|
|
35
|
+
IDocumentServiceFactory,
|
|
36
36
|
IDocumentStorageService,
|
|
37
|
-
IFluidResolvedUrl,
|
|
38
37
|
IResolvedUrl,
|
|
38
|
+
IUrlResolver,
|
|
39
39
|
} from "@fluidframework/driver-definitions";
|
|
40
40
|
import {
|
|
41
41
|
readAndParse,
|
|
42
42
|
OnlineStatus,
|
|
43
43
|
isOnline,
|
|
44
|
-
ensureFluidResolvedUrl,
|
|
45
44
|
combineAppAndProtocolSummary,
|
|
46
45
|
runWithRetry,
|
|
47
|
-
isFluidResolvedUrl,
|
|
48
46
|
isCombinedAppAndProtocolSummary,
|
|
49
47
|
} from "@fluidframework/driver-utils";
|
|
50
48
|
import { IQuorumSnapshot } from "@fluidframework/protocol-base";
|
|
@@ -79,13 +77,14 @@ import {
|
|
|
79
77
|
MonitoringContext,
|
|
80
78
|
loggerToMonitoringContext,
|
|
81
79
|
wrapError,
|
|
80
|
+
ITelemetryLoggerExt,
|
|
82
81
|
} from "@fluidframework/telemetry-utils";
|
|
83
82
|
import { Audience } from "./audience";
|
|
84
83
|
import { ContainerContext } from "./containerContext";
|
|
85
84
|
import { ReconnectMode, IConnectionManagerFactoryArgs, getPackageName } from "./contracts";
|
|
86
85
|
import { DeltaManager, IConnectionArgs } from "./deltaManager";
|
|
87
86
|
import { DeltaManagerProxy } from "./deltaManagerProxy";
|
|
88
|
-
import {
|
|
87
|
+
import { IDetachedBlobStorage, ILoaderOptions, RelativeLoader } from "./loader";
|
|
89
88
|
import { pkgVersion } from "./packageVersion";
|
|
90
89
|
import {
|
|
91
90
|
ContainerStorageAdapter,
|
|
@@ -116,44 +115,82 @@ const dirtyContainerEvent = "dirty";
|
|
|
116
115
|
const savedContainerEvent = "saved";
|
|
117
116
|
|
|
118
117
|
/**
|
|
119
|
-
* @deprecated this is an internal interface and will not longer be exported in future versions
|
|
120
118
|
* @internal
|
|
121
119
|
*/
|
|
122
|
-
export interface
|
|
123
|
-
/**
|
|
124
|
-
* Disables the Container from reconnecting if false, allows reconnect otherwise.
|
|
125
|
-
*/
|
|
126
|
-
canReconnect?: boolean;
|
|
120
|
+
export interface IContainerLoadProps {
|
|
127
121
|
/**
|
|
128
|
-
*
|
|
122
|
+
* The resolved url of the container being loaded
|
|
129
123
|
*/
|
|
130
|
-
|
|
131
|
-
resolvedUrl: IFluidResolvedUrl;
|
|
124
|
+
readonly resolvedUrl: IResolvedUrl;
|
|
132
125
|
/**
|
|
133
126
|
* Control which snapshot version to load from. See IParsedUrl for detailed information.
|
|
134
127
|
*/
|
|
135
|
-
version: string | undefined;
|
|
128
|
+
readonly version: string | undefined;
|
|
136
129
|
/**
|
|
137
130
|
* Loads the Container in paused state if true, unpaused otherwise.
|
|
138
131
|
*/
|
|
139
|
-
loadMode?: IContainerLoadMode;
|
|
132
|
+
readonly loadMode?: IContainerLoadMode;
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* The pending state serialized from a pervious container instance
|
|
136
|
+
*/
|
|
137
|
+
readonly pendingLocalState?: IPendingContainerState;
|
|
140
138
|
}
|
|
141
139
|
|
|
142
140
|
/**
|
|
143
|
-
* @deprecated this is an internal interface and will not longer be exported in future versions
|
|
144
141
|
* @internal
|
|
145
142
|
*/
|
|
146
|
-
export interface
|
|
147
|
-
|
|
148
|
-
|
|
143
|
+
export interface IContainerCreateProps {
|
|
144
|
+
/**
|
|
145
|
+
* Disables the Container from reconnecting if false, allows reconnect otherwise.
|
|
146
|
+
*/
|
|
147
|
+
readonly canReconnect?: boolean;
|
|
149
148
|
/**
|
|
150
149
|
* Client details provided in the override will be merged over the default client.
|
|
151
150
|
*/
|
|
152
|
-
clientDetailsOverride?: IClientDetails;
|
|
151
|
+
readonly clientDetailsOverride?: IClientDetails;
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* The url resolver used by the loader for resolving external urls
|
|
155
|
+
* into Fluid urls such that the container specified by the
|
|
156
|
+
* external url can be loaded.
|
|
157
|
+
*/
|
|
158
|
+
readonly urlResolver: IUrlResolver;
|
|
159
|
+
/**
|
|
160
|
+
* The document service factory take the Fluid url provided
|
|
161
|
+
* by the resolved url and constructs all the necessary services
|
|
162
|
+
* for communication with the container's server.
|
|
163
|
+
*/
|
|
164
|
+
readonly documentServiceFactory: IDocumentServiceFactory;
|
|
153
165
|
/**
|
|
154
|
-
*
|
|
166
|
+
* The code loader handles loading the necessary code
|
|
167
|
+
* for running a container once it is loaded.
|
|
155
168
|
*/
|
|
156
|
-
|
|
169
|
+
readonly codeLoader: ICodeDetailsLoader;
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* A property bag of options used by various layers
|
|
173
|
+
* to control features
|
|
174
|
+
*/
|
|
175
|
+
readonly options: ILoaderOptions;
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Scope is provided to all container and is a set of shared
|
|
179
|
+
* services for container's to integrate with their host environment.
|
|
180
|
+
*/
|
|
181
|
+
readonly scope: FluidObject;
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* The logger downstream consumers should construct their loggers from
|
|
185
|
+
*/
|
|
186
|
+
readonly subLogger: ITelemetryLoggerExt;
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Blobs storage for detached containers.
|
|
190
|
+
*/
|
|
191
|
+
readonly detachedBlobStorage?: IDetachedBlobStorage;
|
|
192
|
+
|
|
193
|
+
readonly protocolHandlerBuilder?: ProtocolHandlerBuilder;
|
|
157
194
|
}
|
|
158
195
|
|
|
159
196
|
/**
|
|
@@ -259,7 +296,7 @@ const getCodeProposal =
|
|
|
259
296
|
* @param action - functor to call and measure
|
|
260
297
|
*/
|
|
261
298
|
export async function ReportIfTooLong(
|
|
262
|
-
logger:
|
|
299
|
+
logger: ITelemetryLoggerExt,
|
|
263
300
|
eventName: string,
|
|
264
301
|
action: () => Promise<ITelemetryProperties>,
|
|
265
302
|
) {
|
|
@@ -273,7 +310,6 @@ export async function ReportIfTooLong(
|
|
|
273
310
|
/**
|
|
274
311
|
* State saved by a container at close time, to be used to load a new instance
|
|
275
312
|
* of the container to the same state
|
|
276
|
-
* @deprecated this is an internal interface and will not longer be exported in future versions
|
|
277
313
|
* @internal
|
|
278
314
|
*/
|
|
279
315
|
export interface IPendingContainerState {
|
|
@@ -300,49 +336,46 @@ export interface IPendingContainerState {
|
|
|
300
336
|
|
|
301
337
|
const summarizerClientType = "summarizer";
|
|
302
338
|
|
|
303
|
-
/**
|
|
304
|
-
* @deprecated - In the next release Container will no longer be exported, IContainer should be used in its place.
|
|
305
|
-
*/
|
|
306
339
|
export class Container
|
|
307
340
|
extends EventEmitterWithErrorHandling<IContainerEvents>
|
|
308
341
|
implements IContainer, IContainerExperimental
|
|
309
342
|
{
|
|
310
343
|
public static version = "^0.1.0";
|
|
311
344
|
|
|
345
|
+
public static async clone(
|
|
346
|
+
container: Container,
|
|
347
|
+
loadProps: IContainerLoadProps,
|
|
348
|
+
createParamOverrides: Partial<IContainerCreateProps>,
|
|
349
|
+
) {
|
|
350
|
+
return this.load(loadProps, {
|
|
351
|
+
...container.createProps,
|
|
352
|
+
...createParamOverrides,
|
|
353
|
+
});
|
|
354
|
+
}
|
|
355
|
+
|
|
312
356
|
/**
|
|
313
357
|
* Load an existing container.
|
|
314
358
|
* @internal
|
|
315
359
|
*/
|
|
316
360
|
public static async load(
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
pendingLocalState?: IPendingContainerState,
|
|
320
|
-
protocolHandlerBuilder?: ProtocolHandlerBuilder,
|
|
361
|
+
loadProps: IContainerLoadProps,
|
|
362
|
+
createProps: IContainerCreateProps,
|
|
321
363
|
): Promise<Container> {
|
|
322
|
-
const
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
clientDetailsOverride: loadOptions.clientDetailsOverride,
|
|
326
|
-
resolvedUrl: loadOptions.resolvedUrl,
|
|
327
|
-
canReconnect: loadOptions.canReconnect,
|
|
328
|
-
serializedContainerState: pendingLocalState,
|
|
329
|
-
},
|
|
330
|
-
protocolHandlerBuilder,
|
|
331
|
-
);
|
|
364
|
+
const { version, pendingLocalState, loadMode, resolvedUrl } = loadProps;
|
|
365
|
+
|
|
366
|
+
const container = new Container(createProps, loadProps);
|
|
332
367
|
|
|
333
368
|
return PerformanceEvent.timedExecAsync(
|
|
334
369
|
container.mc.logger,
|
|
335
370
|
{ eventName: "Load" },
|
|
336
371
|
async (event) =>
|
|
337
372
|
new Promise<Container>((resolve, reject) => {
|
|
338
|
-
const version = loadOptions.version;
|
|
339
|
-
|
|
340
373
|
const defaultMode: IContainerLoadMode = { opsBeforeReturn: "cached" };
|
|
341
374
|
// if we have pendingLocalState, anything we cached is not useful and we shouldn't wait for connection
|
|
342
375
|
// to return container, so ignore this value and use undefined for opsBeforeReturn
|
|
343
376
|
const mode: IContainerLoadMode = pendingLocalState
|
|
344
|
-
? { ...(
|
|
345
|
-
:
|
|
377
|
+
? { ...(loadMode ?? defaultMode), opsBeforeReturn: undefined }
|
|
378
|
+
: loadMode ?? defaultMode;
|
|
346
379
|
|
|
347
380
|
const onClosed = (err?: ICriticalContainerError) => {
|
|
348
381
|
// pre-0.58 error message: containerClosedWithoutErrorDuringLoad
|
|
@@ -353,13 +386,13 @@ export class Container
|
|
|
353
386
|
container.on("closed", onClosed);
|
|
354
387
|
|
|
355
388
|
container
|
|
356
|
-
.load(version, mode, pendingLocalState)
|
|
389
|
+
.load(version, mode, resolvedUrl, pendingLocalState)
|
|
357
390
|
.finally(() => {
|
|
358
391
|
container.removeListener("closed", onClosed);
|
|
359
392
|
})
|
|
360
393
|
.then(
|
|
361
394
|
(props) => {
|
|
362
|
-
event.end({ ...props, ...
|
|
395
|
+
event.end({ ...props, ...loadMode });
|
|
363
396
|
resolve(container);
|
|
364
397
|
},
|
|
365
398
|
(error) => {
|
|
@@ -380,11 +413,10 @@ export class Container
|
|
|
380
413
|
* Create a new container in a detached state.
|
|
381
414
|
*/
|
|
382
415
|
public static async createDetached(
|
|
383
|
-
|
|
416
|
+
createProps: IContainerCreateProps,
|
|
384
417
|
codeDetails: IFluidCodeDetails,
|
|
385
|
-
protocolHandlerBuilder?: ProtocolHandlerBuilder,
|
|
386
418
|
): Promise<Container> {
|
|
387
|
-
const container = new Container(
|
|
419
|
+
const container = new Container(createProps);
|
|
388
420
|
|
|
389
421
|
return PerformanceEvent.timedExecAsync(
|
|
390
422
|
container.mc.logger,
|
|
@@ -402,11 +434,10 @@ export class Container
|
|
|
402
434
|
* snapshot from a previous detached container.
|
|
403
435
|
*/
|
|
404
436
|
public static async rehydrateDetachedFromSnapshot(
|
|
405
|
-
|
|
437
|
+
createProps: IContainerCreateProps,
|
|
406
438
|
snapshot: string,
|
|
407
|
-
protocolHandlerBuilder?: ProtocolHandlerBuilder,
|
|
408
439
|
): Promise<Container> {
|
|
409
|
-
const container = new Container(
|
|
440
|
+
const container = new Container(createProps);
|
|
410
441
|
|
|
411
442
|
return PerformanceEvent.timedExecAsync(
|
|
412
443
|
container.mc.logger,
|
|
@@ -502,7 +533,6 @@ export class Container
|
|
|
502
533
|
private readonly connectionTransitionTimes: number[] = [];
|
|
503
534
|
private messageCountAfterDisconnection: number = 0;
|
|
504
535
|
private _loadedFromVersion: IVersion | undefined;
|
|
505
|
-
private _resolvedUrl: IFluidResolvedUrl | undefined;
|
|
506
536
|
private attachStarted = false;
|
|
507
537
|
private _dirtyContainer = false;
|
|
508
538
|
private readonly savedOps: ISequencedDocumentMessage[] = [];
|
|
@@ -526,7 +556,18 @@ export class Container
|
|
|
526
556
|
}
|
|
527
557
|
|
|
528
558
|
public get resolvedUrl(): IResolvedUrl | undefined {
|
|
529
|
-
|
|
559
|
+
/**
|
|
560
|
+
* All attached containers will have a document service,
|
|
561
|
+
* this is required, as attached containers are attached to
|
|
562
|
+
* a service. Detached containers will neither have a document
|
|
563
|
+
* service or a resolved url as they only exist locally.
|
|
564
|
+
* in order to create a document service a resolved url must
|
|
565
|
+
* first be obtained, this is how the container is identified.
|
|
566
|
+
* Because of this, the document service's resolved url
|
|
567
|
+
* is always the same as the containers, as we had to
|
|
568
|
+
* obtain the resolved url, and then create the service from it.
|
|
569
|
+
*/
|
|
570
|
+
return this.service?.resolvedUrl;
|
|
530
571
|
}
|
|
531
572
|
|
|
532
573
|
public get loadedFromVersion(): IVersion | undefined {
|
|
@@ -632,17 +673,17 @@ export class Container
|
|
|
632
673
|
}
|
|
633
674
|
|
|
634
675
|
private get serviceFactory() {
|
|
635
|
-
return this.
|
|
676
|
+
return this.createProps.documentServiceFactory;
|
|
636
677
|
}
|
|
637
678
|
private get urlResolver() {
|
|
638
|
-
return this.
|
|
679
|
+
return this.createProps.urlResolver;
|
|
639
680
|
}
|
|
640
681
|
public readonly options: ILoaderOptions;
|
|
641
682
|
private get scope() {
|
|
642
|
-
return this.
|
|
683
|
+
return this.createProps.scope;
|
|
643
684
|
}
|
|
644
685
|
private get codeLoader() {
|
|
645
|
-
return this.
|
|
686
|
+
return this.createProps.codeLoader;
|
|
646
687
|
}
|
|
647
688
|
|
|
648
689
|
/**
|
|
@@ -684,9 +725,8 @@ export class Container
|
|
|
684
725
|
* @internal
|
|
685
726
|
*/
|
|
686
727
|
constructor(
|
|
687
|
-
private readonly
|
|
688
|
-
|
|
689
|
-
private readonly protocolHandlerBuilder?: ProtocolHandlerBuilder,
|
|
728
|
+
private readonly createProps: IContainerCreateProps,
|
|
729
|
+
loadProps?: IContainerLoadProps,
|
|
690
730
|
) {
|
|
691
731
|
super((name, error) => {
|
|
692
732
|
this.mc.logger.sendErrorEvent(
|
|
@@ -698,10 +738,9 @@ export class Container
|
|
|
698
738
|
);
|
|
699
739
|
});
|
|
700
740
|
|
|
701
|
-
this.clientDetailsOverride =
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
this._canReconnect = config.canReconnect;
|
|
741
|
+
this.clientDetailsOverride = createProps.clientDetailsOverride;
|
|
742
|
+
if (createProps.canReconnect !== undefined) {
|
|
743
|
+
this._canReconnect = createProps.canReconnect;
|
|
705
744
|
}
|
|
706
745
|
|
|
707
746
|
// Create logger for data stores to use
|
|
@@ -712,15 +751,15 @@ export class Container
|
|
|
712
751
|
}`;
|
|
713
752
|
// Need to use the property getter for docId because for detached flow we don't have the docId initially.
|
|
714
753
|
// We assign the id later so property getter is used.
|
|
715
|
-
this.subLogger = ChildLogger.create(
|
|
754
|
+
this.subLogger = ChildLogger.create(createProps.subLogger, undefined, {
|
|
716
755
|
all: {
|
|
717
756
|
clientType, // Differentiating summarizer container from main container
|
|
718
757
|
containerId: uuid(),
|
|
719
|
-
docId: () => this.
|
|
758
|
+
docId: () => this.resolvedUrl?.id,
|
|
720
759
|
containerAttachState: () => this._attachState,
|
|
721
760
|
containerLifecycleState: () => this._lifecycleState,
|
|
722
761
|
containerConnectionState: () => ConnectionState[this.connectionState],
|
|
723
|
-
serializedContainer:
|
|
762
|
+
serializedContainer: loadProps?.pendingLocalState !== undefined,
|
|
724
763
|
},
|
|
725
764
|
// we need to be judicious with our logging here to avoid generating too much data
|
|
726
765
|
// all data logged here should be broadly applicable, and not specific to a
|
|
@@ -750,7 +789,7 @@ export class Container
|
|
|
750
789
|
// all clients that were loaded from the same loader (including summarizer clients).
|
|
751
790
|
// Tracking alternative ways to handle this in AB#4129.
|
|
752
791
|
this.options = {
|
|
753
|
-
...this.
|
|
792
|
+
...this.createProps.options,
|
|
754
793
|
};
|
|
755
794
|
|
|
756
795
|
this._deltaManager = this.createDeltaManager();
|
|
@@ -758,11 +797,11 @@ export class Container
|
|
|
758
797
|
this.connectionStateHandler = createConnectionStateHandler(
|
|
759
798
|
{
|
|
760
799
|
logger: this.mc.logger,
|
|
761
|
-
connectionStateChanged: (value, oldState, reason) => {
|
|
800
|
+
connectionStateChanged: (value, oldState, reason, error) => {
|
|
762
801
|
if (value === ConnectionState.Connected) {
|
|
763
802
|
this._clientId = this.connectionStateHandler.pendingClientId;
|
|
764
803
|
}
|
|
765
|
-
this.logConnectionStateChangeTelemetry(value, oldState, reason);
|
|
804
|
+
this.logConnectionStateChangeTelemetry(value, oldState, reason, error);
|
|
766
805
|
if (this._lifecycleState === "loaded") {
|
|
767
806
|
this.propagateConnectionState(
|
|
768
807
|
false /* initial transition */,
|
|
@@ -773,7 +812,7 @@ export class Container
|
|
|
773
812
|
}
|
|
774
813
|
},
|
|
775
814
|
shouldClientJoinWrite: () => this._deltaManager.connectionManager.shouldJoinWrite(),
|
|
776
|
-
maxClientLeaveWaitTime: this.
|
|
815
|
+
maxClientLeaveWaitTime: this.createProps.options.maxClientLeaveWaitTime,
|
|
777
816
|
logConnectionIssue: (
|
|
778
817
|
eventName: string,
|
|
779
818
|
category: TelemetryEventCategory,
|
|
@@ -810,7 +849,7 @@ export class Container
|
|
|
810
849
|
},
|
|
811
850
|
},
|
|
812
851
|
this.deltaManager,
|
|
813
|
-
|
|
852
|
+
loadProps?.pendingLocalState?.clientId,
|
|
814
853
|
);
|
|
815
854
|
|
|
816
855
|
this.on(savedContainerEvent, () => {
|
|
@@ -829,12 +868,12 @@ export class Container
|
|
|
829
868
|
// Even if not forced on via this flag, combined summaries may still be enabled by service policy.
|
|
830
869
|
const forceEnableSummarizeProtocolTree =
|
|
831
870
|
this.mc.config.getBoolean("Fluid.Container.summarizeProtocolTree2") ??
|
|
832
|
-
this.
|
|
871
|
+
this.createProps.options.summarizeProtocolTree;
|
|
833
872
|
|
|
834
873
|
this.storageAdapter = new ContainerStorageAdapter(
|
|
835
|
-
this.
|
|
874
|
+
this.createProps.detachedBlobStorage,
|
|
836
875
|
this.mc.logger,
|
|
837
|
-
|
|
876
|
+
loadProps?.pendingLocalState?.snapshotBlobs,
|
|
838
877
|
addProtocolSummaryIfMissing,
|
|
839
878
|
forceEnableSummarizeProtocolTree,
|
|
840
879
|
);
|
|
@@ -868,7 +907,7 @@ export class Container
|
|
|
868
907
|
return this.protocolHandler.quorum;
|
|
869
908
|
}
|
|
870
909
|
|
|
871
|
-
public dispose
|
|
910
|
+
public dispose(error?: ICriticalContainerError) {
|
|
872
911
|
this._deltaManager.close(error, true /* doDispose */);
|
|
873
912
|
this.verifyClosed();
|
|
874
913
|
}
|
|
@@ -920,15 +959,6 @@ export class Container
|
|
|
920
959
|
this._protocolHandler?.close();
|
|
921
960
|
|
|
922
961
|
this.connectionStateHandler.dispose();
|
|
923
|
-
|
|
924
|
-
this._context?.dispose(error !== undefined ? new Error(error.message) : undefined);
|
|
925
|
-
|
|
926
|
-
this.storageAdapter.dispose();
|
|
927
|
-
|
|
928
|
-
// Notify storage about critical errors. They may be due to disconnect between client & server knowledge
|
|
929
|
-
// about file, like file being overwritten in storage, but client having stale local cache.
|
|
930
|
-
// Driver need to ensure all caches are cleared on critical errors
|
|
931
|
-
this.service?.dispose(error);
|
|
932
962
|
} catch (exception) {
|
|
933
963
|
this.mc.logger.sendErrorEvent({ eventName: "ContainerCloseException" }, exception);
|
|
934
964
|
}
|
|
@@ -1048,10 +1078,7 @@ export class Container
|
|
|
1048
1078
|
const protocolSummary = this.captureProtocolSummary();
|
|
1049
1079
|
const combinedSummary = combineAppAndProtocolSummary(appSummary, protocolSummary);
|
|
1050
1080
|
|
|
1051
|
-
if (
|
|
1052
|
-
this.loader.services.detachedBlobStorage &&
|
|
1053
|
-
this.loader.services.detachedBlobStorage.size > 0
|
|
1054
|
-
) {
|
|
1081
|
+
if (this.createProps.detachedBlobStorage && this.createProps.detachedBlobStorage.size > 0) {
|
|
1055
1082
|
combinedSummary.tree[".hasAttachmentBlobs"] = {
|
|
1056
1083
|
type: SummaryType.Blob,
|
|
1057
1084
|
content: "true",
|
|
@@ -1081,8 +1108,8 @@ export class Container
|
|
|
1081
1108
|
|
|
1082
1109
|
// If attachment blobs were uploaded in detached state we will go through a different attach flow
|
|
1083
1110
|
const hasAttachmentBlobs =
|
|
1084
|
-
this.
|
|
1085
|
-
this.
|
|
1111
|
+
this.createProps.detachedBlobStorage !== undefined &&
|
|
1112
|
+
this.createProps.detachedBlobStorage.size > 0;
|
|
1086
1113
|
|
|
1087
1114
|
try {
|
|
1088
1115
|
assert(
|
|
@@ -1113,11 +1140,11 @@ export class Container
|
|
|
1113
1140
|
}
|
|
1114
1141
|
|
|
1115
1142
|
// Actually go and create the resolved document
|
|
1116
|
-
const createNewResolvedUrl = await this.urlResolver.resolve(request);
|
|
1117
|
-
ensureFluidResolvedUrl(createNewResolvedUrl);
|
|
1118
1143
|
if (this.service === undefined) {
|
|
1144
|
+
const createNewResolvedUrl = await this.urlResolver.resolve(request);
|
|
1119
1145
|
assert(
|
|
1120
|
-
this.client.details.type !== summarizerClientType
|
|
1146
|
+
this.client.details.type !== summarizerClientType &&
|
|
1147
|
+
createNewResolvedUrl !== undefined,
|
|
1121
1148
|
0x2c4 /* "client should not be summarizer before container is created" */,
|
|
1122
1149
|
);
|
|
1123
1150
|
this.service = await runWithRetry(
|
|
@@ -1135,15 +1162,12 @@ export class Container
|
|
|
1135
1162
|
}, // progress
|
|
1136
1163
|
);
|
|
1137
1164
|
}
|
|
1138
|
-
const resolvedUrl = this.service.resolvedUrl;
|
|
1139
|
-
ensureFluidResolvedUrl(resolvedUrl);
|
|
1140
|
-
this._resolvedUrl = resolvedUrl;
|
|
1141
1165
|
await this.storageAdapter.connectToService(this.service);
|
|
1142
1166
|
|
|
1143
1167
|
if (hasAttachmentBlobs) {
|
|
1144
1168
|
// upload blobs to storage
|
|
1145
1169
|
assert(
|
|
1146
|
-
!!this.
|
|
1170
|
+
!!this.createProps.detachedBlobStorage,
|
|
1147
1171
|
0x24e /* "assertion for type narrowing" */,
|
|
1148
1172
|
);
|
|
1149
1173
|
|
|
@@ -1151,13 +1175,14 @@ export class Container
|
|
|
1151
1175
|
// support blob handles that only know about the local IDs
|
|
1152
1176
|
const redirectTable = new Map<string, string>();
|
|
1153
1177
|
// if new blobs are added while uploading, upload them too
|
|
1154
|
-
while (redirectTable.size < this.
|
|
1155
|
-
const newIds = this.
|
|
1178
|
+
while (redirectTable.size < this.createProps.detachedBlobStorage.size) {
|
|
1179
|
+
const newIds = this.createProps.detachedBlobStorage
|
|
1156
1180
|
.getBlobIds()
|
|
1157
1181
|
.filter((id) => !redirectTable.has(id));
|
|
1158
1182
|
for (const id of newIds) {
|
|
1159
|
-
const blob =
|
|
1160
|
-
|
|
1183
|
+
const blob = await this.createProps.detachedBlobStorage.readBlob(
|
|
1184
|
+
id,
|
|
1185
|
+
);
|
|
1161
1186
|
const response = await this.storageAdapter.createBlob(blob);
|
|
1162
1187
|
redirectTable.set(id, response.id);
|
|
1163
1188
|
}
|
|
@@ -1196,12 +1221,8 @@ export class Container
|
|
|
1196
1221
|
} catch (error) {
|
|
1197
1222
|
// add resolved URL on error object so that host has the ability to find this document and delete it
|
|
1198
1223
|
const newError = normalizeError(error);
|
|
1199
|
-
|
|
1200
|
-
if (isFluidResolvedUrl(resolvedUrl)) {
|
|
1201
|
-
newError.addTelemetryProperties({ resolvedUrl: resolvedUrl.url });
|
|
1202
|
-
}
|
|
1224
|
+
newError.addTelemetryProperties({ resolvedUrl: this.resolvedUrl?.url });
|
|
1203
1225
|
this.close(newError);
|
|
1204
|
-
this.dispose?.(newError);
|
|
1205
1226
|
throw newError;
|
|
1206
1227
|
}
|
|
1207
1228
|
},
|
|
@@ -1348,7 +1369,6 @@ export class Container
|
|
|
1348
1369
|
// pre-0.58 error message: existingContextDoesNotSatisfyIncomingProposal
|
|
1349
1370
|
const error = new GenericError("Existing context does not satisfy incoming proposal");
|
|
1350
1371
|
this.close(error);
|
|
1351
|
-
this.dispose?.(error);
|
|
1352
1372
|
}
|
|
1353
1373
|
|
|
1354
1374
|
private async getVersion(version: string | null): Promise<IVersion | undefined> {
|
|
@@ -1381,13 +1401,11 @@ export class Container
|
|
|
1381
1401
|
private async load(
|
|
1382
1402
|
specifiedVersion: string | undefined,
|
|
1383
1403
|
loadMode: IContainerLoadMode,
|
|
1404
|
+
resolvedUrl: IResolvedUrl,
|
|
1384
1405
|
pendingLocalState?: IPendingContainerState,
|
|
1385
1406
|
) {
|
|
1386
|
-
if (this._resolvedUrl === undefined) {
|
|
1387
|
-
throw new Error("Attempting to load without a resolved url");
|
|
1388
|
-
}
|
|
1389
1407
|
this.service = await this.serviceFactory.createDocumentService(
|
|
1390
|
-
|
|
1408
|
+
resolvedUrl,
|
|
1391
1409
|
this.subLogger,
|
|
1392
1410
|
this.client.details.type === summarizerClientType,
|
|
1393
1411
|
);
|
|
@@ -1419,7 +1437,6 @@ export class Container
|
|
|
1419
1437
|
// if we have pendingLocalState we can load without storage; don't wait for connection
|
|
1420
1438
|
this.storageAdapter.connectToService(this.service).catch((error) => {
|
|
1421
1439
|
this.close(error);
|
|
1422
|
-
this.dispose?.(error);
|
|
1423
1440
|
});
|
|
1424
1441
|
}
|
|
1425
1442
|
|
|
@@ -1602,8 +1619,8 @@ export class Container
|
|
|
1602
1619
|
private async rehydrateDetachedFromSnapshot(detachedContainerSnapshot: ISummaryTree) {
|
|
1603
1620
|
if (detachedContainerSnapshot.tree[".hasAttachmentBlobs"] !== undefined) {
|
|
1604
1621
|
assert(
|
|
1605
|
-
!!this.
|
|
1606
|
-
this.
|
|
1622
|
+
!!this.createProps.detachedBlobStorage &&
|
|
1623
|
+
this.createProps.detachedBlobStorage.size > 0,
|
|
1607
1624
|
0x250 /* "serialized container with attachment blobs must be rehydrated with detached blob storage" */,
|
|
1608
1625
|
);
|
|
1609
1626
|
delete detachedContainerSnapshot.tree[".hasAttachmentBlobs"];
|
|
@@ -1701,7 +1718,7 @@ export class Container
|
|
|
1701
1718
|
quorumSnapshot: IQuorumSnapshot,
|
|
1702
1719
|
): void {
|
|
1703
1720
|
const protocolHandlerBuilder =
|
|
1704
|
-
this.protocolHandlerBuilder ??
|
|
1721
|
+
this.createProps.protocolHandlerBuilder ??
|
|
1705
1722
|
((...args) => new ProtocolHandler(...args, new Audience()));
|
|
1706
1723
|
const protocol = protocolHandlerBuilder(attributes, quorumSnapshot, (key, value) =>
|
|
1707
1724
|
this.submitMessage(MessageType.Propose, JSON.stringify({ key, value })),
|
|
@@ -1732,7 +1749,6 @@ export class Container
|
|
|
1732
1749
|
this.processCodeProposal().catch((error) => {
|
|
1733
1750
|
const normalizedError = normalizeError(error);
|
|
1734
1751
|
this.close(normalizedError);
|
|
1735
|
-
this.dispose?.(normalizedError);
|
|
1736
1752
|
throw error;
|
|
1737
1753
|
});
|
|
1738
1754
|
}
|
|
@@ -1843,10 +1859,10 @@ export class Container
|
|
|
1843
1859
|
this.connectionStateHandler.receivedConnectEvent(details);
|
|
1844
1860
|
});
|
|
1845
1861
|
|
|
1846
|
-
deltaManager.on("disconnect", (reason: string) => {
|
|
1862
|
+
deltaManager.on("disconnect", (reason: string, error?: IAnyDriverError) => {
|
|
1847
1863
|
this.collabWindowTracker?.stopSequenceNumberUpdate();
|
|
1848
1864
|
if (!this.closed) {
|
|
1849
|
-
this.connectionStateHandler.receivedDisconnectEvent(reason);
|
|
1865
|
+
this.connectionStateHandler.receivedDisconnectEvent(reason, error);
|
|
1850
1866
|
}
|
|
1851
1867
|
});
|
|
1852
1868
|
|
|
@@ -1900,6 +1916,7 @@ export class Container
|
|
|
1900
1916
|
value: ConnectionState,
|
|
1901
1917
|
oldState: ConnectionState,
|
|
1902
1918
|
reason?: string,
|
|
1919
|
+
error?: IAnyDriverError,
|
|
1903
1920
|
) {
|
|
1904
1921
|
// Log actual event
|
|
1905
1922
|
const time = performance.now();
|
|
@@ -1928,24 +1945,29 @@ export class Container
|
|
|
1928
1945
|
connectionInitiationReason = this.firstConnection ? "InitialConnect" : "AutoReconnect";
|
|
1929
1946
|
}
|
|
1930
1947
|
|
|
1931
|
-
this.mc.logger.sendPerformanceEvent(
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1948
|
+
this.mc.logger.sendPerformanceEvent(
|
|
1949
|
+
{
|
|
1950
|
+
eventName: `ConnectionStateChange_${ConnectionState[value]}`,
|
|
1951
|
+
from: ConnectionState[oldState],
|
|
1952
|
+
duration,
|
|
1953
|
+
durationFromDisconnected,
|
|
1954
|
+
reason,
|
|
1955
|
+
connectionInitiationReason,
|
|
1956
|
+
pendingClientId: this.connectionStateHandler.pendingClientId,
|
|
1957
|
+
clientId: this.clientId,
|
|
1958
|
+
autoReconnect,
|
|
1959
|
+
opsBehind,
|
|
1960
|
+
online: OnlineStatus[isOnline()],
|
|
1961
|
+
lastVisible:
|
|
1962
|
+
this.lastVisible !== undefined
|
|
1963
|
+
? performance.now() - this.lastVisible
|
|
1964
|
+
: undefined,
|
|
1965
|
+
checkpointSequenceNumber,
|
|
1966
|
+
quorumSize: this._protocolHandler?.quorum.getMembers().size,
|
|
1967
|
+
...this._deltaManager.connectionProps,
|
|
1968
|
+
},
|
|
1969
|
+
error,
|
|
1970
|
+
);
|
|
1949
1971
|
|
|
1950
1972
|
if (value === ConnectionState.Connected) {
|
|
1951
1973
|
this.firstConnection = false;
|
|
@@ -2006,7 +2028,6 @@ export class Container
|
|
|
2006
2028
|
{ messageType: type },
|
|
2007
2029
|
);
|
|
2008
2030
|
this.close(newError);
|
|
2009
|
-
this.dispose?.(newError);
|
|
2010
2031
|
return -1;
|
|
2011
2032
|
}
|
|
2012
2033
|
}
|
|
@@ -2176,7 +2197,8 @@ export class Container
|
|
|
2176
2197
|
|
|
2177
2198
|
// The relative loader will proxy requests to '/' to the loader itself assuming no non-cache flags
|
|
2178
2199
|
// are set. Global requests will still go directly to the loader
|
|
2179
|
-
const
|
|
2200
|
+
const maybeLoader: FluidObject<IHostLoader> = this.scope;
|
|
2201
|
+
const loader = new RelativeLoader(this, maybeLoader.ILoader);
|
|
2180
2202
|
this._context = await ContainerContext.createOrLoad(
|
|
2181
2203
|
this,
|
|
2182
2204
|
this.scope,
|
|
@@ -2193,7 +2215,7 @@ export class Container
|
|
|
2193
2215
|
(batch: IBatchMessage[], referenceSequenceNumber?: number) =>
|
|
2194
2216
|
this.submitBatch(batch, referenceSequenceNumber),
|
|
2195
2217
|
(message) => this.submitSignal(message),
|
|
2196
|
-
(error?: ICriticalContainerError) => this.dispose
|
|
2218
|
+
(error?: ICriticalContainerError) => this.dispose(error),
|
|
2197
2219
|
(error?: ICriticalContainerError) => this.close(error),
|
|
2198
2220
|
Container.version,
|
|
2199
2221
|
(dirty: boolean) => this.updateDirtyContainerState(dirty),
|