@fluidframework/container-loader 1.0.0 → 1.1.0-76254
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/dist/connectionManager.d.ts.map +1 -1
- package/dist/connectionManager.js +3 -1
- package/dist/connectionManager.js.map +1 -1
- package/dist/connectionStateHandler.d.ts +44 -10
- package/dist/connectionStateHandler.d.ts.map +1 -1
- package/dist/connectionStateHandler.js +90 -35
- package/dist/connectionStateHandler.js.map +1 -1
- package/dist/container.d.ts +2 -2
- package/dist/container.d.ts.map +1 -1
- package/dist/container.js +48 -70
- package/dist/container.js.map +1 -1
- package/dist/containerStorageAdapter.d.ts +2 -2
- package/dist/containerStorageAdapter.d.ts.map +1 -1
- package/dist/containerStorageAdapter.js +4 -4
- package/dist/containerStorageAdapter.js.map +1 -1
- package/dist/contracts.d.ts +1 -1
- package/dist/contracts.js +1 -1
- package/dist/contracts.js.map +1 -1
- package/dist/deltaManager.d.ts.map +1 -1
- package/dist/deltaManager.js +9 -1
- package/dist/deltaManager.js.map +1 -1
- package/dist/deltaQueue.d.ts.map +1 -1
- package/dist/deltaQueue.js +8 -3
- package/dist/deltaQueue.js.map +1 -1
- package/dist/packageVersion.d.ts +1 -1
- package/dist/packageVersion.d.ts.map +1 -1
- package/dist/packageVersion.js +1 -1
- package/dist/packageVersion.js.map +1 -1
- package/dist/protocolTreeDocumentStorageService.d.ts +2 -2
- package/dist/protocolTreeDocumentStorageService.d.ts.map +1 -1
- package/dist/retriableDocumentStorageService.d.ts +2 -2
- package/dist/retriableDocumentStorageService.d.ts.map +1 -1
- package/dist/retriableDocumentStorageService.js +4 -4
- package/dist/retriableDocumentStorageService.js.map +1 -1
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +3 -2
- package/dist/utils.js.map +1 -1
- package/lib/connectionManager.d.ts.map +1 -1
- package/lib/connectionManager.js +4 -2
- package/lib/connectionManager.js.map +1 -1
- package/lib/connectionStateHandler.d.ts +44 -10
- package/lib/connectionStateHandler.d.ts.map +1 -1
- package/lib/connectionStateHandler.js +90 -35
- package/lib/connectionStateHandler.js.map +1 -1
- package/lib/container.d.ts +2 -2
- package/lib/container.d.ts.map +1 -1
- package/lib/container.js +49 -71
- package/lib/container.js.map +1 -1
- package/lib/containerStorageAdapter.d.ts +2 -2
- package/lib/containerStorageAdapter.d.ts.map +1 -1
- package/lib/containerStorageAdapter.js +4 -4
- package/lib/containerStorageAdapter.js.map +1 -1
- package/lib/contracts.d.ts +1 -1
- package/lib/contracts.js +1 -1
- package/lib/contracts.js.map +1 -1
- package/lib/deltaManager.d.ts.map +1 -1
- package/lib/deltaManager.js +9 -1
- package/lib/deltaManager.js.map +1 -1
- package/lib/deltaQueue.d.ts.map +1 -1
- package/lib/deltaQueue.js +8 -3
- package/lib/deltaQueue.js.map +1 -1
- package/lib/packageVersion.d.ts +1 -1
- package/lib/packageVersion.d.ts.map +1 -1
- package/lib/packageVersion.js +1 -1
- package/lib/packageVersion.js.map +1 -1
- package/lib/protocolTreeDocumentStorageService.d.ts +2 -2
- package/lib/protocolTreeDocumentStorageService.d.ts.map +1 -1
- package/lib/retriableDocumentStorageService.d.ts +2 -2
- package/lib/retriableDocumentStorageService.d.ts.map +1 -1
- package/lib/retriableDocumentStorageService.js +4 -4
- package/lib/retriableDocumentStorageService.js.map +1 -1
- package/lib/utils.d.ts.map +1 -1
- package/lib/utils.js +3 -2
- package/lib/utils.js.map +1 -1
- package/package.json +15 -28
- package/src/connectionManager.ts +4 -6
- package/src/connectionStateHandler.ts +113 -54
- package/src/container.ts +66 -89
- package/src/containerStorageAdapter.ts +4 -4
- package/src/contracts.ts +1 -1
- package/src/deltaManager.ts +8 -2
- package/src/deltaQueue.ts +7 -3
- package/src/packageVersion.ts +1 -1
- package/src/retriableDocumentStorageService.ts +4 -4
- package/src/utils.ts +3 -2
package/src/container.ts
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
import merge from "lodash/merge";
|
|
8
8
|
import { v4 as uuid } from "uuid";
|
|
9
9
|
import {
|
|
10
|
-
IDisposable,
|
|
10
|
+
IDisposable, ITelemetryProperties,
|
|
11
11
|
} from "@fluidframework/common-definitions";
|
|
12
12
|
import { assert, performance, unreachableCase } from "@fluidframework/common-utils";
|
|
13
13
|
import {
|
|
@@ -53,7 +53,8 @@ import {
|
|
|
53
53
|
} from "@fluidframework/driver-utils";
|
|
54
54
|
import {
|
|
55
55
|
isSystemMessage,
|
|
56
|
-
|
|
56
|
+
IProtocolHandler,
|
|
57
|
+
ProtocolOpHandlerWithClientValidation,
|
|
57
58
|
} from "@fluidframework/protocol-base";
|
|
58
59
|
import {
|
|
59
60
|
IClient,
|
|
@@ -98,7 +99,7 @@ import { DeltaManager, IConnectionArgs } from "./deltaManager";
|
|
|
98
99
|
import { DeltaManagerProxy } from "./deltaManagerProxy";
|
|
99
100
|
import { ILoaderOptions, Loader, RelativeLoader } from "./loader";
|
|
100
101
|
import { pkgVersion } from "./packageVersion";
|
|
101
|
-
import { ConnectionStateHandler
|
|
102
|
+
import { ConnectionStateHandler } from "./connectionStateHandler";
|
|
102
103
|
import { RetriableDocumentStorageService } from "./retriableDocumentStorageService";
|
|
103
104
|
import { ProtocolTreeStorageService } from "./protocolTreeDocumentStorageService";
|
|
104
105
|
import { BlobOnlyStorage, ContainerStorageAdapter } from "./containerStorageAdapter";
|
|
@@ -262,7 +263,6 @@ export class Container extends EventEmitterWithErrorHandling<IContainerEvents> i
|
|
|
262
263
|
container.mc.logger,
|
|
263
264
|
{ eventName: "Load" },
|
|
264
265
|
async (event) => new Promise<Container>((resolve, reject) => {
|
|
265
|
-
container._lifecycleState = "loading";
|
|
266
266
|
const version = loadOptions.version;
|
|
267
267
|
|
|
268
268
|
const defaultMode: IContainerLoadMode = { opsBeforeReturn: "cached" };
|
|
@@ -314,7 +314,6 @@ export class Container extends EventEmitterWithErrorHandling<IContainerEvents> i
|
|
|
314
314
|
container.mc.logger,
|
|
315
315
|
{ eventName: "CreateDetached" },
|
|
316
316
|
async (_event) => {
|
|
317
|
-
container._lifecycleState = "loading";
|
|
318
317
|
await container.createDetached(codeDetails);
|
|
319
318
|
return container;
|
|
320
319
|
},
|
|
@@ -337,7 +336,6 @@ export class Container extends EventEmitterWithErrorHandling<IContainerEvents> i
|
|
|
337
336
|
{ eventName: "RehydrateDetachedFromSnapshot" },
|
|
338
337
|
async (_event) => {
|
|
339
338
|
const deserializedSummary = JSON.parse(snapshot) as ISummaryTree;
|
|
340
|
-
container._lifecycleState = "loading";
|
|
341
339
|
await container.rehydrateDetachedFromSnapshot(deserializedSummary);
|
|
342
340
|
return container;
|
|
343
341
|
},
|
|
@@ -352,19 +350,14 @@ export class Container extends EventEmitterWithErrorHandling<IContainerEvents> i
|
|
|
352
350
|
|
|
353
351
|
private readonly mc: MonitoringContext;
|
|
354
352
|
|
|
355
|
-
private _lifecycleState: "
|
|
356
|
-
|
|
357
|
-
private get loaded(): boolean {
|
|
358
|
-
return (this._lifecycleState !== "created" && this._lifecycleState !== "loading");
|
|
359
|
-
}
|
|
360
|
-
|
|
361
|
-
private set loaded(t: boolean) {
|
|
362
|
-
assert(t, 0x27d /* "Setting loaded state to false is not supported" */);
|
|
363
|
-
assert(this._lifecycleState !== "created", 0x27e /* "Must go through loading state before loaded" */);
|
|
353
|
+
private _lifecycleState: "loading" | "loaded" | "closing" | "closed" = "loading";
|
|
364
354
|
|
|
355
|
+
private setLoaded() {
|
|
365
356
|
// It's conceivable the container could be closed when this is called
|
|
366
357
|
// Only transition states if currently loading
|
|
367
358
|
if (this._lifecycleState === "loading") {
|
|
359
|
+
// Propagate current connection state through the system.
|
|
360
|
+
this.propagateConnectionState();
|
|
368
361
|
this._lifecycleState = "loaded";
|
|
369
362
|
}
|
|
370
363
|
}
|
|
@@ -400,7 +393,7 @@ export class Container extends EventEmitterWithErrorHandling<IContainerEvents> i
|
|
|
400
393
|
}
|
|
401
394
|
return this._context;
|
|
402
395
|
}
|
|
403
|
-
private _protocolHandler:
|
|
396
|
+
private _protocolHandler: IProtocolHandler | undefined;
|
|
404
397
|
private get protocolHandler() {
|
|
405
398
|
if (this._protocolHandler === undefined) {
|
|
406
399
|
throw new Error("Attempted to access protocolHandler before it was defined");
|
|
@@ -608,16 +601,18 @@ export class Container extends EventEmitterWithErrorHandling<IContainerEvents> i
|
|
|
608
601
|
this.logConnectionStateChangeTelemetry(value, oldState, reason),
|
|
609
602
|
shouldClientJoinWrite: () => this._deltaManager.connectionManager.shouldJoinWrite(),
|
|
610
603
|
maxClientLeaveWaitTime: this.loader.services.options.maxClientLeaveWaitTime,
|
|
611
|
-
logConnectionIssue: (eventName: string) => {
|
|
604
|
+
logConnectionIssue: (eventName: string, details?: ITelemetryProperties) => {
|
|
612
605
|
// We get here when socket does not receive any ops on "write" connection, including
|
|
613
606
|
// its own join op. Attempt recovery option.
|
|
614
607
|
this._deltaManager.logConnectionIssue({
|
|
615
608
|
eventName,
|
|
616
609
|
duration: performance.now() - this.connectionTransitionTimes[ConnectionState.CatchingUp],
|
|
610
|
+
...(details === undefined ? {} : { details: JSON.stringify(details) }),
|
|
617
611
|
});
|
|
618
612
|
},
|
|
619
613
|
connectionStateChanged: () => {
|
|
620
|
-
if
|
|
614
|
+
// Fire events only if container is fully loaded and not closed
|
|
615
|
+
if (this._lifecycleState === "loaded") {
|
|
621
616
|
this.propagateConnectionState();
|
|
622
617
|
}
|
|
623
618
|
},
|
|
@@ -708,16 +703,34 @@ export class Container extends EventEmitterWithErrorHandling<IContainerEvents> i
|
|
|
708
703
|
}
|
|
709
704
|
|
|
710
705
|
public close(error?: ICriticalContainerError) {
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
706
|
+
// 1. Ensure that close sequence is exactly the same no matter if it's initiated by host or by DeltaManager
|
|
707
|
+
// 2. We need to ensure that we deliver disconnect event to runtime properly. See connectionStateChanged
|
|
708
|
+
// handler. We only deliver events if container fully loaded. Transitioning from "loading" ->
|
|
709
|
+
// "closing" will lose that info (can also solve by tracking extra state).
|
|
710
|
+
this._deltaManager.close(error);
|
|
711
|
+
assert(this.connectionState === ConnectionState.Disconnected,
|
|
712
|
+
0x0cf /* "disconnect event was not raised!" */);
|
|
714
713
|
|
|
715
|
-
|
|
716
|
-
|
|
714
|
+
assert(this._lifecycleState === "closed", 0x314 /* Container properly closed */);
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
private closeCore(error?: ICriticalContainerError) {
|
|
718
|
+
assert(!this.closed, 0x315 /* re-entrancy */);
|
|
717
719
|
|
|
720
|
+
try {
|
|
718
721
|
// Ensure that we raise all key events even if one of these throws
|
|
719
722
|
try {
|
|
720
|
-
|
|
723
|
+
// Raise event first, to ensure we capture _lifecycleState before transition.
|
|
724
|
+
// This gives us a chance to know what errors happened on open vs. on fully loaded container.
|
|
725
|
+
this.mc.logger.sendTelemetryEvent(
|
|
726
|
+
{
|
|
727
|
+
eventName: "ContainerClose",
|
|
728
|
+
category: error === undefined ? "generic" : "error",
|
|
729
|
+
},
|
|
730
|
+
error,
|
|
731
|
+
);
|
|
732
|
+
|
|
733
|
+
this._lifecycleState = "closing";
|
|
721
734
|
|
|
722
735
|
this._protocolHandler?.close();
|
|
723
736
|
|
|
@@ -725,9 +738,6 @@ export class Container extends EventEmitterWithErrorHandling<IContainerEvents> i
|
|
|
725
738
|
|
|
726
739
|
this._context?.dispose(error !== undefined ? new Error(error.message) : undefined);
|
|
727
740
|
|
|
728
|
-
assert(this.connectionState === ConnectionState.Disconnected,
|
|
729
|
-
0x0cf /* "disconnect event was not raised!" */);
|
|
730
|
-
|
|
731
741
|
this._storageService?.dispose();
|
|
732
742
|
|
|
733
743
|
// Notify storage about critical errors. They may be due to disconnect between client & server knowledge
|
|
@@ -738,14 +748,6 @@ export class Container extends EventEmitterWithErrorHandling<IContainerEvents> i
|
|
|
738
748
|
this.mc.logger.sendErrorEvent({ eventName: "ContainerCloseException" }, exception);
|
|
739
749
|
}
|
|
740
750
|
|
|
741
|
-
this.mc.logger.sendTelemetryEvent(
|
|
742
|
-
{
|
|
743
|
-
eventName: "ContainerClose",
|
|
744
|
-
category: error === undefined ? "generic" : "error",
|
|
745
|
-
},
|
|
746
|
-
error,
|
|
747
|
-
);
|
|
748
|
-
|
|
749
751
|
this.emit("closed", error);
|
|
750
752
|
|
|
751
753
|
this.removeAllListeners();
|
|
@@ -766,11 +768,13 @@ export class Container extends EventEmitterWithErrorHandling<IContainerEvents> i
|
|
|
766
768
|
assert(this.resolvedUrl !== undefined && this.resolvedUrl.type === "fluid",
|
|
767
769
|
0x0d2 /* "resolved url should be valid Fluid url" */);
|
|
768
770
|
assert(!!this._protocolHandler, 0x2e3 /* "Must have a valid protocol handler instance" */);
|
|
771
|
+
assert(this._protocolHandler.attributes.term !== undefined,
|
|
772
|
+
0x30b /* Must have a valid protocol handler instance */);
|
|
769
773
|
const pendingState: IPendingContainerState = {
|
|
770
774
|
pendingRuntimeState: this.context.getPendingLocalState(),
|
|
771
775
|
url: this.resolvedUrl.url,
|
|
772
|
-
protocol: this.
|
|
773
|
-
term: this._protocolHandler.term,
|
|
776
|
+
protocol: this.protocolHandler.getProtocolState(),
|
|
777
|
+
term: this._protocolHandler.attributes.term,
|
|
774
778
|
clientId: this.clientId,
|
|
775
779
|
};
|
|
776
780
|
|
|
@@ -1167,11 +1171,8 @@ export class Container extends EventEmitterWithErrorHandling<IContainerEvents> i
|
|
|
1167
1171
|
pendingLocalState?.pendingRuntimeState,
|
|
1168
1172
|
);
|
|
1169
1173
|
|
|
1170
|
-
// Propagate current connection state through the system.
|
|
1171
|
-
this.propagateConnectionState();
|
|
1172
|
-
|
|
1173
1174
|
// Internal context is fully loaded at this point
|
|
1174
|
-
this.
|
|
1175
|
+
this.setLoaded();
|
|
1175
1176
|
|
|
1176
1177
|
// We might have hit some failure that did not manifest itself in exception in this flow,
|
|
1177
1178
|
// do not start op processing in such case - static version of Container.load() will handle it correctly.
|
|
@@ -1243,9 +1244,7 @@ export class Container extends EventEmitterWithErrorHandling<IContainerEvents> i
|
|
|
1243
1244
|
false, // existing
|
|
1244
1245
|
);
|
|
1245
1246
|
|
|
1246
|
-
this.
|
|
1247
|
-
|
|
1248
|
-
this.loaded = true;
|
|
1247
|
+
this.setLoaded();
|
|
1249
1248
|
}
|
|
1250
1249
|
|
|
1251
1250
|
private async rehydrateDetachedFromSnapshot(detachedContainerSnapshot: ISummaryTree) {
|
|
@@ -1280,9 +1279,7 @@ export class Container extends EventEmitterWithErrorHandling<IContainerEvents> i
|
|
|
1280
1279
|
snapshotTree,
|
|
1281
1280
|
);
|
|
1282
1281
|
|
|
1283
|
-
this.
|
|
1284
|
-
|
|
1285
|
-
this.propagateConnectionState();
|
|
1282
|
+
this.setLoaded();
|
|
1286
1283
|
}
|
|
1287
1284
|
|
|
1288
1285
|
private async connectStorageService(): Promise<void> {
|
|
@@ -1338,7 +1335,7 @@ export class Container extends EventEmitterWithErrorHandling<IContainerEvents> i
|
|
|
1338
1335
|
attributes: IDocumentAttributes,
|
|
1339
1336
|
storage: IDocumentStorageService,
|
|
1340
1337
|
snapshot: ISnapshotTree | undefined,
|
|
1341
|
-
): Promise<
|
|
1338
|
+
): Promise<IProtocolHandler> {
|
|
1342
1339
|
let members: [string, ISequencedClient][] = [];
|
|
1343
1340
|
let proposals: [number, ISequencedProposal, string[]][] = [];
|
|
1344
1341
|
let values: [string, any][] = [];
|
|
@@ -1366,8 +1363,8 @@ export class Container extends EventEmitterWithErrorHandling<IContainerEvents> i
|
|
|
1366
1363
|
members: [string, ISequencedClient][],
|
|
1367
1364
|
proposals: [number, ISequencedProposal, string[]][],
|
|
1368
1365
|
values: [string, any][],
|
|
1369
|
-
): Promise<
|
|
1370
|
-
const protocol = new
|
|
1366
|
+
): Promise<IProtocolHandler> {
|
|
1367
|
+
const protocol = new ProtocolOpHandlerWithClientValidation(
|
|
1371
1368
|
attributes.minimumSequenceNumber,
|
|
1372
1369
|
attributes.sequenceNumber,
|
|
1373
1370
|
attributes.term,
|
|
@@ -1412,19 +1409,11 @@ export class Container extends EventEmitterWithErrorHandling<IContainerEvents> i
|
|
|
1412
1409
|
}
|
|
1413
1410
|
|
|
1414
1411
|
private captureProtocolSummary(): ISummaryTree {
|
|
1415
|
-
const quorumSnapshot = this.protocolHandler.
|
|
1416
|
-
|
|
1417
|
-
// Save attributes for the document
|
|
1418
|
-
const documentAttributes: IDocumentAttributes = {
|
|
1419
|
-
minimumSequenceNumber: this.protocolHandler.minimumSequenceNumber,
|
|
1420
|
-
sequenceNumber: this.protocolHandler.sequenceNumber,
|
|
1421
|
-
term: this.protocolHandler.term,
|
|
1422
|
-
};
|
|
1423
|
-
|
|
1412
|
+
const quorumSnapshot = this.protocolHandler.snapshot();
|
|
1424
1413
|
const summary: ISummaryTree = {
|
|
1425
1414
|
tree: {
|
|
1426
1415
|
attributes: {
|
|
1427
|
-
content: JSON.stringify(
|
|
1416
|
+
content: JSON.stringify(this.protocolHandler.attributes),
|
|
1428
1417
|
type: SummaryType.Blob,
|
|
1429
1418
|
},
|
|
1430
1419
|
quorumMembers: {
|
|
@@ -1539,7 +1528,7 @@ export class Container extends EventEmitterWithErrorHandling<IContainerEvents> i
|
|
|
1539
1528
|
});
|
|
1540
1529
|
|
|
1541
1530
|
deltaManager.on("closed", (error?: ICriticalContainerError) => {
|
|
1542
|
-
this.
|
|
1531
|
+
this.closeCore(error);
|
|
1543
1532
|
});
|
|
1544
1533
|
|
|
1545
1534
|
return deltaManager;
|
|
@@ -1629,11 +1618,13 @@ export class Container extends EventEmitterWithErrorHandling<IContainerEvents> i
|
|
|
1629
1618
|
}
|
|
1630
1619
|
|
|
1631
1620
|
const state = this.connectionState === ConnectionState.Connected;
|
|
1632
|
-
|
|
1621
|
+
|
|
1622
|
+
// Both protocol and context should not be undefined if we got so far.
|
|
1623
|
+
|
|
1624
|
+
if (this._context?.disposed === false) {
|
|
1633
1625
|
this.context.setConnectionState(state, this.clientId);
|
|
1634
1626
|
}
|
|
1635
|
-
|
|
1636
|
-
this.protocolHandler.quorum.setConnectionState(state, this.clientId);
|
|
1627
|
+
this.protocolHandler.setConnectionState(state, this.clientId);
|
|
1637
1628
|
raiseConnectedEvent(this.mc.logger, this, state, this.clientId);
|
|
1638
1629
|
|
|
1639
1630
|
if (logOpsOnReconnect) {
|
|
@@ -1682,36 +1673,22 @@ export class Container extends EventEmitterWithErrorHandling<IContainerEvents> i
|
|
|
1682
1673
|
}
|
|
1683
1674
|
|
|
1684
1675
|
private processRemoteMessage(message: ISequencedDocumentMessage): IProcessMessageResult {
|
|
1685
|
-
// Check and report if we're getting messages from a clientId that we previously
|
|
1686
|
-
// flagged as shouldHaveLeft, or from a client that's not in the quorum but should be
|
|
1687
|
-
if (message.clientId != null) {
|
|
1688
|
-
let errorMsg: string | undefined;
|
|
1689
|
-
const client: ILocalSequencedClient | undefined =
|
|
1690
|
-
this.getQuorum().getMember(message.clientId);
|
|
1691
|
-
if (client === undefined && message.type !== MessageType.ClientJoin) {
|
|
1692
|
-
// pre-0.58 error message: messageClientIdMissingFromQuorum
|
|
1693
|
-
errorMsg = "Remote message's clientId is missing from the quorum";
|
|
1694
|
-
} else if (client?.shouldHaveLeft === true && message.type !== MessageType.NoOp) {
|
|
1695
|
-
// pre-0.58 error message: messageClientIdShouldHaveLeft
|
|
1696
|
-
errorMsg = "Remote message's clientId already should have left";
|
|
1697
|
-
}
|
|
1698
|
-
if (errorMsg !== undefined) {
|
|
1699
|
-
const error = new DataCorruptionError(
|
|
1700
|
-
errorMsg,
|
|
1701
|
-
extractSafePropertiesFromMessage(message));
|
|
1702
|
-
this.close(normalizeError(error));
|
|
1703
|
-
}
|
|
1704
|
-
}
|
|
1705
|
-
|
|
1706
1676
|
const local = this.clientId === message.clientId;
|
|
1707
1677
|
|
|
1678
|
+
// Allow the protocol handler to process the message
|
|
1679
|
+
let result: IProcessMessageResult = { immediateNoOp: false };
|
|
1680
|
+
try {
|
|
1681
|
+
result = this.protocolHandler.processMessage(message, local);
|
|
1682
|
+
} catch (error) {
|
|
1683
|
+
this.close(wrapError(error, (errorMessage) =>
|
|
1684
|
+
new DataCorruptionError(errorMessage, extractSafePropertiesFromMessage(message))));
|
|
1685
|
+
}
|
|
1686
|
+
|
|
1708
1687
|
// Forward non system messages to the loaded runtime for processing
|
|
1709
1688
|
if (!isSystemMessage(message)) {
|
|
1710
1689
|
this.context.process(message, local, undefined);
|
|
1711
1690
|
}
|
|
1712
1691
|
|
|
1713
|
-
// Allow the protocol handler to process the message
|
|
1714
|
-
const result = this.protocolHandler.processMessage(message, local);
|
|
1715
1692
|
// Inactive (not in quorum or not writers) clients don't take part in the minimum sequence number calculation.
|
|
1716
1693
|
if (this.activeConnection()) {
|
|
1717
1694
|
if (this.collabWindowTracker === undefined) {
|
|
@@ -1728,8 +1705,8 @@ export class Container extends EventEmitterWithErrorHandling<IContainerEvents> i
|
|
|
1728
1705
|
0x241 /* "disconnect should result in stopSequenceNumberUpdate() call" */);
|
|
1729
1706
|
this.submitMessage(type, contents);
|
|
1730
1707
|
},
|
|
1731
|
-
this.serviceConfiguration
|
|
1732
|
-
this.serviceConfiguration
|
|
1708
|
+
this.serviceConfiguration.noopTimeFrequency,
|
|
1709
|
+
this.serviceConfiguration.noopCountFrequency,
|
|
1733
1710
|
);
|
|
1734
1711
|
}
|
|
1735
1712
|
this.collabWindowTracker.scheduleSequenceNumberUpdate(message, result.immediateNoOp === true);
|
|
@@ -53,8 +53,8 @@ export class ContainerStorageAdapter implements IDocumentStorageService {
|
|
|
53
53
|
return this.storageGetter().repositoryUrl;
|
|
54
54
|
}
|
|
55
55
|
|
|
56
|
-
public async getSnapshotTree(version?: IVersion): Promise<ISnapshotTree | null> {
|
|
57
|
-
return this.storageGetter().getSnapshotTree(version);
|
|
56
|
+
public async getSnapshotTree(version?: IVersion, scenarioName?: string): Promise<ISnapshotTree | null> {
|
|
57
|
+
return this.storageGetter().getSnapshotTree(version, scenarioName);
|
|
58
58
|
}
|
|
59
59
|
|
|
60
60
|
public async readBlob(id: string): Promise<ArrayBufferLike> {
|
|
@@ -65,8 +65,8 @@ export class ContainerStorageAdapter implements IDocumentStorageService {
|
|
|
65
65
|
return this.storageGetter().readBlob(id);
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
-
public async getVersions(versionId: string | null, count: number): Promise<IVersion[]> {
|
|
69
|
-
return this.storageGetter().getVersions(versionId, count);
|
|
68
|
+
public async getVersions(versionId: string | null, count: number, scenarioName?: string): Promise<IVersion[]> {
|
|
69
|
+
return this.storageGetter().getVersions(versionId, count, scenarioName);
|
|
70
70
|
}
|
|
71
71
|
|
|
72
72
|
public async uploadSummaryWithContext(summary: ISummaryTree, context: ISummaryContext): Promise<string> {
|
package/src/contracts.ts
CHANGED
|
@@ -163,7 +163,7 @@ export interface IConnectionManagerFactoryArgs {
|
|
|
163
163
|
|
|
164
164
|
/**
|
|
165
165
|
*
|
|
166
|
-
* @param codeDetails- Data structure used to describe the code to load on the Fluid document
|
|
166
|
+
* @param codeDetails- - Data structure used to describe the code to load on the Fluid document
|
|
167
167
|
* @returns The name of the Fluid package
|
|
168
168
|
*/
|
|
169
169
|
export const getPackageName = (codeDetails: IFluidCodeDetails | undefined): IContainerPackageInfo => {
|
package/src/deltaManager.ts
CHANGED
|
@@ -267,8 +267,14 @@ export class DeltaManager<TConnectionManager extends IConnectionManager>
|
|
|
267
267
|
) {
|
|
268
268
|
super();
|
|
269
269
|
const props: IConnectionManagerFactoryArgs = {
|
|
270
|
-
incomingOpHandler: (messages: ISequencedDocumentMessage[], reason: string) =>
|
|
271
|
-
|
|
270
|
+
incomingOpHandler: (messages: ISequencedDocumentMessage[], reason: string) => {
|
|
271
|
+
try {
|
|
272
|
+
this.enqueueMessages(messages, reason);
|
|
273
|
+
} catch (error) {
|
|
274
|
+
this.logger.sendErrorEvent({ eventName: "EnqueueMessages_Exception" }, error);
|
|
275
|
+
this.close(normalizeError(error));
|
|
276
|
+
}
|
|
277
|
+
},
|
|
272
278
|
signalHandler: (message: ISignalMessage) => this._inboundSignal.push(message),
|
|
273
279
|
reconnectionDelayHandler: (delayMs: number, error: unknown) =>
|
|
274
280
|
this.emitDelayInfo(this.deltaStreamDelayId, delayMs, error),
|
package/src/deltaQueue.ts
CHANGED
|
@@ -85,9 +85,13 @@ export class DeltaQueue<T>
|
|
|
85
85
|
}
|
|
86
86
|
|
|
87
87
|
public push(task: T) {
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
88
|
+
try {
|
|
89
|
+
this.q.push(task);
|
|
90
|
+
this.emit("push", task);
|
|
91
|
+
this.ensureProcessing();
|
|
92
|
+
} catch (error) {
|
|
93
|
+
this.emit("error", error);
|
|
94
|
+
}
|
|
91
95
|
}
|
|
92
96
|
|
|
93
97
|
public async pause(): Promise<void> {
|
package/src/packageVersion.ts
CHANGED
|
@@ -40,9 +40,9 @@ export class RetriableDocumentStorageService implements IDocumentStorageService,
|
|
|
40
40
|
return this.internalStorageService.repositoryUrl;
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
-
public async getSnapshotTree(version?: IVersion): Promise<ISnapshotTree | null> {
|
|
43
|
+
public async getSnapshotTree(version?: IVersion, scenarioName?: string): Promise<ISnapshotTree | null> {
|
|
44
44
|
return this.runWithRetry(
|
|
45
|
-
async () => this.internalStorageService.getSnapshotTree(version),
|
|
45
|
+
async () => this.internalStorageService.getSnapshotTree(version, scenarioName),
|
|
46
46
|
"storage_getSnapshotTree",
|
|
47
47
|
);
|
|
48
48
|
}
|
|
@@ -54,9 +54,9 @@ export class RetriableDocumentStorageService implements IDocumentStorageService,
|
|
|
54
54
|
);
|
|
55
55
|
}
|
|
56
56
|
|
|
57
|
-
public async getVersions(versionId: string | null, count: number): Promise<IVersion[]> {
|
|
57
|
+
public async getVersions(versionId: string | null, count: number, scenarioName?: string): Promise<IVersion[]> {
|
|
58
58
|
return this.runWithRetry(
|
|
59
|
-
async () => this.internalStorageService.getVersions(versionId, count),
|
|
59
|
+
async () => this.internalStorageService.getVersions(versionId, count, scenarioName),
|
|
60
60
|
"storage_getVersions",
|
|
61
61
|
);
|
|
62
62
|
}
|
package/src/utils.ts
CHANGED
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
unreachableCase,
|
|
13
13
|
} from "@fluidframework/common-utils";
|
|
14
14
|
import { ISummaryTree, ISnapshotTree, SummaryType } from "@fluidframework/protocol-definitions";
|
|
15
|
+
import { LoggingError } from "@fluidframework/telemetry-utils";
|
|
15
16
|
|
|
16
17
|
// This is used when we rehydrate a container from the snapshot. Here we put the blob contents
|
|
17
18
|
// in separate property: blobContents.
|
|
@@ -35,7 +36,7 @@ export interface IParsedUrl {
|
|
|
35
36
|
export function parseUrl(url: string): IParsedUrl | undefined {
|
|
36
37
|
const parsed = parse(url, true);
|
|
37
38
|
if (typeof parsed.pathname !== "string") {
|
|
38
|
-
throw new
|
|
39
|
+
throw new LoggingError("Failed to parse pathname");
|
|
39
40
|
}
|
|
40
41
|
const query = parsed.search ?? "";
|
|
41
42
|
const regex = /^\/([^/]*\/[^/]*)(\/?.*)$/;
|
|
@@ -86,7 +87,7 @@ function convertSummaryToSnapshotWithEmbeddedBlobContents(
|
|
|
86
87
|
break;
|
|
87
88
|
}
|
|
88
89
|
case SummaryType.Handle:
|
|
89
|
-
throw new
|
|
90
|
+
throw new LoggingError("No handles should be there in summary in detached container!!");
|
|
90
91
|
break;
|
|
91
92
|
default: {
|
|
92
93
|
unreachableCase(summaryObject, `Unknown tree type ${(summaryObject as any).type}`);
|