@fluidframework/container-runtime 2.70.0-361248 → 2.70.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 +10 -0
- package/container-runtime.test-files.tar +0 -0
- package/dist/blobManager/blobManager.d.ts.map +1 -1
- package/dist/blobManager/blobManager.js +0 -1
- package/dist/blobManager/blobManager.js.map +1 -1
- package/dist/containerRuntime.d.ts +25 -6
- package/dist/containerRuntime.d.ts.map +1 -1
- package/dist/containerRuntime.js +92 -22
- package/dist/containerRuntime.js.map +1 -1
- package/dist/dataStore.d.ts +1 -1
- package/dist/dataStore.d.ts.map +1 -1
- package/dist/dataStore.js +7 -8
- package/dist/dataStore.js.map +1 -1
- package/dist/dataStoreContext.d.ts.map +1 -1
- package/dist/dataStoreContext.js +1 -1
- package/dist/dataStoreContext.js.map +1 -1
- package/dist/opLifecycle/outbox.d.ts.map +1 -1
- package/dist/opLifecycle/outbox.js +7 -0
- package/dist/opLifecycle/outbox.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/runtimeLayerCompatState.d.ts +4 -3
- package/dist/runtimeLayerCompatState.d.ts.map +1 -1
- package/dist/runtimeLayerCompatState.js +4 -35
- package/dist/runtimeLayerCompatState.js.map +1 -1
- package/dist/storageServiceWithAttachBlobs.d.ts +0 -36
- package/dist/storageServiceWithAttachBlobs.d.ts.map +1 -1
- package/dist/storageServiceWithAttachBlobs.js +0 -55
- package/dist/storageServiceWithAttachBlobs.js.map +1 -1
- package/lib/blobManager/blobManager.d.ts.map +1 -1
- package/lib/blobManager/blobManager.js +0 -1
- package/lib/blobManager/blobManager.js.map +1 -1
- package/lib/containerRuntime.d.ts +25 -6
- package/lib/containerRuntime.d.ts.map +1 -1
- package/lib/containerRuntime.js +92 -22
- package/lib/containerRuntime.js.map +1 -1
- package/lib/dataStore.d.ts +1 -1
- package/lib/dataStore.d.ts.map +1 -1
- package/lib/dataStore.js +2 -3
- package/lib/dataStore.js.map +1 -1
- package/lib/dataStoreContext.d.ts.map +1 -1
- package/lib/dataStoreContext.js +1 -1
- package/lib/dataStoreContext.js.map +1 -1
- package/lib/opLifecycle/outbox.d.ts.map +1 -1
- package/lib/opLifecycle/outbox.js +7 -0
- package/lib/opLifecycle/outbox.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/runtimeLayerCompatState.d.ts +4 -3
- package/lib/runtimeLayerCompatState.d.ts.map +1 -1
- package/lib/runtimeLayerCompatState.js +5 -36
- package/lib/runtimeLayerCompatState.js.map +1 -1
- package/lib/storageServiceWithAttachBlobs.d.ts +0 -36
- package/lib/storageServiceWithAttachBlobs.d.ts.map +1 -1
- package/lib/storageServiceWithAttachBlobs.js +0 -55
- package/lib/storageServiceWithAttachBlobs.js.map +1 -1
- package/package.json +20 -17
- package/src/blobManager/blobManager.ts +0 -1
- package/src/containerRuntime.ts +144 -37
- package/src/dataStore.ts +6 -9
- package/src/dataStoreContext.ts +1 -0
- package/src/opLifecycle/outbox.ts +10 -0
- package/src/packageVersion.ts +1 -1
- package/src/runtimeLayerCompatState.ts +23 -39
- package/src/storageServiceWithAttachBlobs.ts +0 -92
package/dist/containerRuntime.js
CHANGED
|
@@ -460,6 +460,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
460
460
|
};
|
|
461
461
|
const runtime = new containerRuntimeCtor(context, registry, metadata, electedSummarizerData, chunks ?? [], aliases ?? [], internalRuntimeOptions, containerScope, logger, existing, blobManagerLoadInfo, context.storage, createIdCompressorFn, documentSchemaController, featureGatesForTelemetry, provideEntryPoint, (0, internal_7.semanticVersionToMinimumVersionForCollab)(updatedMinVersionForCollab), requestHandler, undefined, // summaryConfiguration
|
|
462
462
|
recentBatchInfo);
|
|
463
|
+
runtime.sharePendingBlobs();
|
|
463
464
|
// Initialize the base state of the runtime before it's returned.
|
|
464
465
|
await runtime.initializeBaseState(context.loader);
|
|
465
466
|
// Apply stashed ops with a reference sequence number equal to the sequence number of the snapshot,
|
|
@@ -627,9 +628,8 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
627
628
|
* Enter Staging Mode, such that ops submitted to the ContainerRuntime will not be sent to the ordering service.
|
|
628
629
|
* To exit Staging Mode, call either discardChanges or commitChanges on the Stage Controls returned from this method.
|
|
629
630
|
*
|
|
630
|
-
* @returns
|
|
631
|
+
* @returns Controls for exiting Staging Mode.
|
|
631
632
|
*/
|
|
632
|
-
// eslint-disable-next-line import/no-deprecated
|
|
633
633
|
this.enterStagingMode = () => {
|
|
634
634
|
if (this.stageControls !== undefined) {
|
|
635
635
|
throw new internal_8.UsageError("Already in staging mode");
|
|
@@ -658,7 +658,6 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
658
658
|
throw normalizedError;
|
|
659
659
|
}
|
|
660
660
|
};
|
|
661
|
-
// eslint-disable-next-line import/no-deprecated
|
|
662
661
|
const stageControls = {
|
|
663
662
|
discardChanges: () => exitStagingMode(() => {
|
|
664
663
|
// Pop all staged batches from the PSM and roll them back in LIFO order
|
|
@@ -684,6 +683,39 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
684
683
|
return this.stageControls;
|
|
685
684
|
};
|
|
686
685
|
this.readAndParseBlob = async (id) => (0, internal_4.readAndParse)(this.storage, id);
|
|
686
|
+
/**
|
|
687
|
+
* ContainerRuntime knows about additional restrictions on when blob sharing can be resumed as compared
|
|
688
|
+
* to BlobManager. In particular, it wants to avoid sharing blobs while in readonly state, and it also
|
|
689
|
+
* wants to avoid sharing blobs before connection completes (otherwise it may cause the sharing to happen
|
|
690
|
+
* before processing shared ops).
|
|
691
|
+
*
|
|
692
|
+
* This method can be called safely before those conditions are met. In the background, it will wait until
|
|
693
|
+
* it is safe before initiating sharing. It will close the container on any error.
|
|
694
|
+
*/
|
|
695
|
+
this.sharePendingBlobs = () => {
|
|
696
|
+
new Promise((resolve) => {
|
|
697
|
+
// eslint-disable-next-line unicorn/consistent-function-scoping
|
|
698
|
+
const canStartSharing = () => this.connected && this.deltaManager.readOnlyInfo.readonly !== true;
|
|
699
|
+
if (canStartSharing()) {
|
|
700
|
+
resolve();
|
|
701
|
+
return;
|
|
702
|
+
}
|
|
703
|
+
const checkCanShare = (readonly) => {
|
|
704
|
+
if (canStartSharing()) {
|
|
705
|
+
this.deltaManager.off("readonly", checkCanShare);
|
|
706
|
+
this.off("connected", checkCanShare);
|
|
707
|
+
resolve();
|
|
708
|
+
}
|
|
709
|
+
};
|
|
710
|
+
this.deltaManager.on("readonly", checkCanShare);
|
|
711
|
+
this.on("connected", checkCanShare);
|
|
712
|
+
})
|
|
713
|
+
.then(this.blobManager.sharePendingBlobs)
|
|
714
|
+
// It may not be necessary to close the container on failures - this should just mean there's
|
|
715
|
+
// a handle in the container that is stuck pending, which is a scenario that customers need to
|
|
716
|
+
// handle anyway. Starting with this more aggressive/restrictive behavior to be cautious.
|
|
717
|
+
.catch(this.closeFn);
|
|
718
|
+
};
|
|
687
719
|
// While internal, ContainerRuntime has not been converted to use the new events support.
|
|
688
720
|
// Recreate the required events (new pattern) with injected, wrapper new emitter.
|
|
689
721
|
// It is lazily create to avoid listeners (old events) that ultimately go nowhere.
|
|
@@ -694,7 +726,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
694
726
|
eventEmitter.emit("joined", { clientId, canWrite });
|
|
695
727
|
});
|
|
696
728
|
this.on("disconnectedFromService", () => eventEmitter.emit("disconnected"));
|
|
697
|
-
this.on("
|
|
729
|
+
this.on("operabilityChanged", (canWrite) => eventEmitter.emit("operabilityChanged", canWrite));
|
|
698
730
|
}
|
|
699
731
|
else {
|
|
700
732
|
this.on("connected", (clientId) => {
|
|
@@ -704,14 +736,11 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
704
736
|
}
|
|
705
737
|
return eventEmitter;
|
|
706
738
|
});
|
|
707
|
-
const { options, clientDetails, connected, baseSnapshot, submitFn, submitBatchFn, submitSummaryFn, submitSignalFn, disposeFn, closeFn, deltaManager, quorum, audience, pendingLocalState, supportedFeatures, snapshotWithContents, getConnectionState, } = context;
|
|
739
|
+
const { options, clientDetails, connected, baseSnapshot, submitFn, submitBatchFn, submitSummaryFn, submitSignalFn, disposeFn, closeFn, deltaManager, quorum, audience, signalAudience, pendingLocalState, supportedFeatures, snapshotWithContents, getConnectionState, } = context;
|
|
708
740
|
this.getConnectionState = getConnectionState;
|
|
709
741
|
// In old loaders without dispose functionality, closeFn is equivalent but will also switch container to readonly mode
|
|
710
742
|
this.disposeFn = disposeFn ?? closeFn;
|
|
711
743
|
this.isSnapshotInstanceOfISnapshot = snapshotWithContents !== undefined;
|
|
712
|
-
// Validate that the Loader is compatible with this Runtime.
|
|
713
|
-
const maybeLoaderCompatDetailsForRuntime = context;
|
|
714
|
-
(0, runtimeLayerCompatState_js_1.validateLoaderCompatibility)(maybeLoaderCompatDetailsForRuntime.ILayerCompatDetails, this.disposeFn);
|
|
715
744
|
this.mc = (0, internal_8.createChildMonitoringContext)({
|
|
716
745
|
logger: this.baseLogger,
|
|
717
746
|
namespace: "ContainerRuntime",
|
|
@@ -721,6 +750,9 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
721
750
|
},
|
|
722
751
|
},
|
|
723
752
|
});
|
|
753
|
+
// Validate that the Loader is compatible with this Runtime.
|
|
754
|
+
const maybeLoaderCompatDetailsForRuntime = context;
|
|
755
|
+
(0, runtimeLayerCompatState_js_1.validateLoaderCompatibility)(maybeLoaderCompatDetailsForRuntime.ILayerCompatDetails, this.disposeFn, this.mc.logger);
|
|
724
756
|
// If we support multiple algorithms in the future, then we would need to manage it here carefully.
|
|
725
757
|
// We can use runtimeOptions.compressionOptions.compressionAlgorithm, but only if it's in the schema list!
|
|
726
758
|
// If it's not in the list, then we will need to either use no compression, or fallback to some other (supported by format)
|
|
@@ -820,10 +852,11 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
820
852
|
this.nextSummaryNumber = loadSummaryNumber + 1;
|
|
821
853
|
this.messageAtLastSummary = lastMessageFromMetadata(metadata);
|
|
822
854
|
// Note that we only need to pull the *initial* connected state from the context.
|
|
823
|
-
// Later updates come through calls to setConnectionState.
|
|
855
|
+
// Later updates come through calls to setConnectionState/Status.
|
|
824
856
|
this.canSendOps = connected;
|
|
825
857
|
this.canSendSignals = this.getConnectionState
|
|
826
|
-
? this.getConnectionState() === internal_1.ConnectionState.Connected
|
|
858
|
+
? this.getConnectionState() === internal_1.ConnectionState.Connected ||
|
|
859
|
+
this.getConnectionState() === internal_1.ConnectionState.CatchingUp
|
|
827
860
|
: undefined;
|
|
828
861
|
this.mc.logger.sendTelemetryEvent({
|
|
829
862
|
eventName: "GCFeatureMatrix",
|
|
@@ -1047,6 +1080,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
1047
1080
|
oldClientId = clientId;
|
|
1048
1081
|
});
|
|
1049
1082
|
}
|
|
1083
|
+
this.signalAudience = signalAudience;
|
|
1050
1084
|
const closeSummarizerDelayOverride = this.mc.config.getNumber("Fluid.ContainerRuntime.Test.CloseSummarizerDelayOverrideMs");
|
|
1051
1085
|
this.closeSummarizerDelayMs =
|
|
1052
1086
|
closeSummarizerDelayOverride ?? defaultCloseSummarizerDelayMs;
|
|
@@ -1628,6 +1662,38 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
1628
1662
|
}
|
|
1629
1663
|
}
|
|
1630
1664
|
setConnectionState(canSendOps, clientId) {
|
|
1665
|
+
this.setConnectionStateToConnectedOrDisconnected(canSendOps, clientId);
|
|
1666
|
+
}
|
|
1667
|
+
setConnectionStatus(status) {
|
|
1668
|
+
switch (status.connectionState) {
|
|
1669
|
+
case internal_1.ConnectionState.Connected: {
|
|
1670
|
+
this.setConnectionStateToConnectedOrDisconnected(status.canSendOps, status.clientConnectionId);
|
|
1671
|
+
break;
|
|
1672
|
+
}
|
|
1673
|
+
case internal_1.ConnectionState.Disconnected: {
|
|
1674
|
+
this.setConnectionStateToConnectedOrDisconnected(status.canSendOps, status.priorConnectedClientConnectionId);
|
|
1675
|
+
break;
|
|
1676
|
+
}
|
|
1677
|
+
case internal_1.ConnectionState.CatchingUp: {
|
|
1678
|
+
(0, internal_2.assert)(this.getConnectionState !== undefined &&
|
|
1679
|
+
this.getConnectionState() === internal_1.ConnectionState.CatchingUp, 0xc8d /* connection state mismatch between getConnectionState and setConnectionStatus notification */);
|
|
1680
|
+
// Note: Historically when only `setConnectionState` of `IRuntime`
|
|
1681
|
+
// was supported, it was possible to be in `CatchingUp` state and
|
|
1682
|
+
// call through to `setConnectionStateCore` when there is a readonly
|
|
1683
|
+
// change - see `Container`'s `"deltaManager.on("readonly"`. There
|
|
1684
|
+
// would not be a transition of `canSendOps` in that case, but
|
|
1685
|
+
// `channelCollection` and `garbageCollector` would receive early
|
|
1686
|
+
// `setConnectionState` call AND `this` would `emit` "disconnected"
|
|
1687
|
+
// event.
|
|
1688
|
+
this.emitServiceConnectionEvents(
|
|
1689
|
+
/* canSendOpsChanged */ this.canSendOps,
|
|
1690
|
+
/* canSendOps */ false, status.pendingClientConnectionId);
|
|
1691
|
+
break;
|
|
1692
|
+
}
|
|
1693
|
+
// No default
|
|
1694
|
+
}
|
|
1695
|
+
}
|
|
1696
|
+
setConnectionStateToConnectedOrDisconnected(canSendOps, clientId) {
|
|
1631
1697
|
// Validate we have consistent state
|
|
1632
1698
|
const currentClientId = this._audience.getSelf()?.clientId;
|
|
1633
1699
|
(0, internal_2.assert)(clientId === currentClientId, 0x977 /* input clientId does not match Audience */);
|
|
@@ -1686,30 +1752,33 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
1686
1752
|
* Emits service connection events based on connection state changes.
|
|
1687
1753
|
*
|
|
1688
1754
|
* @remarks
|
|
1689
|
-
* "connectedToService" is emitted when container connection state transitions to 'Connected' regardless of connection mode.
|
|
1755
|
+
* "connectedToService" is emitted when container connection state transitions to 'CatchingUp' or 'Connected' regardless of connection mode.
|
|
1690
1756
|
* "disconnectedFromService" excludes false "disconnected" events that happen when readonly client transitions to 'Connected'.
|
|
1691
1757
|
*/
|
|
1692
1758
|
emitServiceConnectionEvents(canSendOpsChanged, canSendOps, clientId) {
|
|
1693
1759
|
if (!this.getConnectionState) {
|
|
1694
1760
|
return;
|
|
1695
1761
|
}
|
|
1696
|
-
const
|
|
1762
|
+
const connectionState = this.getConnectionState();
|
|
1763
|
+
const canSendSignals = connectionState === internal_1.ConnectionState.Connected ||
|
|
1764
|
+
connectionState === internal_1.ConnectionState.CatchingUp;
|
|
1697
1765
|
const canSendSignalsChanged = this.canSendSignals !== canSendSignals;
|
|
1698
1766
|
this.canSendSignals = canSendSignals;
|
|
1699
1767
|
if (canSendSignalsChanged) {
|
|
1700
|
-
// If canSendSignals changed, we either transitioned from
|
|
1768
|
+
// If canSendSignals changed, we either transitioned from CatchingUp or
|
|
1769
|
+
// Connected to Disconnected or EstablishingConnection to CatchingUp.
|
|
1701
1770
|
if (canSendSignals) {
|
|
1702
|
-
// Emit for
|
|
1771
|
+
// Emit for EstablishingConnection to CatchingUp or Connected transition
|
|
1703
1772
|
this.emit("connectedToService", clientId, canSendOps);
|
|
1704
1773
|
}
|
|
1705
1774
|
else {
|
|
1706
|
-
// Emit for Connected to Disconnected transition
|
|
1775
|
+
// Emit for CatchingUp or Connected to Disconnected transition
|
|
1707
1776
|
this.emit("disconnectedFromService");
|
|
1708
1777
|
}
|
|
1709
1778
|
}
|
|
1710
1779
|
else if (canSendOpsChanged) {
|
|
1711
|
-
// If canSendSignals did not change but canSendOps did, then
|
|
1712
|
-
this.emit("
|
|
1780
|
+
// If canSendSignals did not change but canSendOps did, then operations possible has changed.
|
|
1781
|
+
this.emit("operabilityChanged", canSendOps);
|
|
1713
1782
|
}
|
|
1714
1783
|
}
|
|
1715
1784
|
async notifyOpReplay(message) {
|
|
@@ -2100,7 +2169,6 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
2100
2169
|
*/
|
|
2101
2170
|
orderSequentially(callback) {
|
|
2102
2171
|
let checkpoint;
|
|
2103
|
-
// eslint-disable-next-line import/no-deprecated
|
|
2104
2172
|
let stageControls;
|
|
2105
2173
|
if (this.mc.config.getBoolean("Fluid.ContainerRuntime.EnableRollback") === true) {
|
|
2106
2174
|
if (!this.batchRunner.running && !this.inStagingMode) {
|
|
@@ -2841,7 +2909,6 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
2841
2909
|
// TODO: better typing
|
|
2842
2910
|
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any
|
|
2843
2911
|
contents, localOpMetadata = undefined) {
|
|
2844
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
2845
2912
|
this.submit({ type, contents }, localOpMetadata);
|
|
2846
2913
|
}
|
|
2847
2914
|
async uploadBlob(blob, signal) {
|
|
@@ -3310,7 +3377,9 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
3310
3377
|
const getConnectionState = this.getConnectionState;
|
|
3311
3378
|
if (getConnectionState) {
|
|
3312
3379
|
const connectionState = getConnectionState();
|
|
3313
|
-
if (connectionState === internal_1.ConnectionState.Connected
|
|
3380
|
+
if (connectionState === internal_1.ConnectionState.Connected ||
|
|
3381
|
+
connectionState === internal_1.ConnectionState.CatchingUp) {
|
|
3382
|
+
// Note: when CatchingUp, canSendOps will always be false.
|
|
3314
3383
|
return this.canSendOps ? "joinedForWriting" : "joinedForReading";
|
|
3315
3384
|
}
|
|
3316
3385
|
}
|
|
@@ -3322,16 +3391,17 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
3322
3391
|
acquireExtension(id, factory, ...useContext) {
|
|
3323
3392
|
let entry = this.extensions.get(id);
|
|
3324
3393
|
if (entry === undefined) {
|
|
3394
|
+
const audience = this.signalAudience;
|
|
3325
3395
|
const runtime = {
|
|
3326
3396
|
getJoinedStatus: this.getJoinedStatus.bind(this),
|
|
3327
|
-
getClientId: () => this.clientId,
|
|
3397
|
+
getClientId: audience ? () => audience.getSelf()?.clientId : () => this.clientId,
|
|
3328
3398
|
events: this.lazyEventsForExtensions.value,
|
|
3329
3399
|
logger: this.baseLogger,
|
|
3330
3400
|
submitAddressedSignal: (addressChain, message) => {
|
|
3331
3401
|
this.submitExtensionSignal(id, addressChain, message);
|
|
3332
3402
|
},
|
|
3333
3403
|
getQuorum: this.getQuorum.bind(this),
|
|
3334
|
-
getAudience: this.getAudience.bind(this),
|
|
3404
|
+
getAudience: audience ? () => audience : this.getAudience.bind(this),
|
|
3335
3405
|
supportedFeatures: this.ILayerCompatDetails.supportedFeatures,
|
|
3336
3406
|
};
|
|
3337
3407
|
entry = new factory(runtime, ...useContext);
|