@fluidframework/container-runtime 2.91.0 → 2.92.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 +4 -0
- package/api-report/container-runtime.legacy.beta.api.md +2 -0
- package/container-runtime.test-files.tar +0 -0
- package/dist/containerCompatibility.d.ts +1 -1
- package/dist/containerCompatibility.d.ts.map +1 -1
- package/dist/containerCompatibility.js.map +1 -1
- package/dist/containerRuntime.d.ts +36 -9
- package/dist/containerRuntime.d.ts.map +1 -1
- package/dist/containerRuntime.js +97 -54
- package/dist/containerRuntime.js.map +1 -1
- package/dist/gc/garbageCollection.d.ts +1 -0
- package/dist/gc/garbageCollection.d.ts.map +1 -1
- package/dist/gc/garbageCollection.js +3 -8
- package/dist/gc/garbageCollection.js.map +1 -1
- package/dist/gc/gcDefinitions.d.ts +4 -0
- package/dist/gc/gcDefinitions.d.ts.map +1 -1
- package/dist/gc/gcDefinitions.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/legacy.d.ts +1 -1
- package/dist/opLifecycle/batchManager.d.ts.map +1 -1
- package/dist/opLifecycle/batchManager.js +2 -1
- package/dist/opLifecycle/batchManager.js.map +1 -1
- package/dist/opLifecycle/index.d.ts +1 -1
- package/dist/opLifecycle/index.d.ts.map +1 -1
- package/dist/opLifecycle/index.js +2 -1
- package/dist/opLifecycle/index.js.map +1 -1
- package/dist/opLifecycle/opGroupingManager.d.ts +6 -0
- package/dist/opLifecycle/opGroupingManager.d.ts.map +1 -1
- package/dist/opLifecycle/opGroupingManager.js +11 -2
- package/dist/opLifecycle/opGroupingManager.js.map +1 -1
- package/dist/opLifecycle/opSerialization.d.ts +3 -1
- package/dist/opLifecycle/opSerialization.d.ts.map +1 -1
- package/dist/opLifecycle/opSerialization.js +11 -9
- package/dist/opLifecycle/opSerialization.js.map +1 -1
- package/dist/opLifecycle/outbox.d.ts +0 -6
- package/dist/opLifecycle/outbox.d.ts.map +1 -1
- package/dist/opLifecycle/outbox.js +2 -9
- package/dist/opLifecycle/outbox.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/pendingStateManager.d.ts +7 -3
- package/dist/pendingStateManager.d.ts.map +1 -1
- package/dist/pendingStateManager.js +19 -7
- package/dist/pendingStateManager.js.map +1 -1
- package/dist/public.d.ts +1 -1
- package/dist/runtimeLayerCompatState.d.ts +1 -1
- package/dist/summary/documentSchema.d.ts +9 -3
- package/dist/summary/documentSchema.d.ts.map +1 -1
- package/dist/summary/documentSchema.js +19 -3
- package/dist/summary/documentSchema.js.map +1 -1
- package/dist/summary/orderedClientElection.js +2 -2
- package/dist/summary/orderedClientElection.js.map +1 -1
- package/dist/summary/summaryManager.d.ts +1 -0
- package/dist/summary/summaryManager.d.ts.map +1 -1
- package/dist/summary/summaryManager.js +9 -0
- package/dist/summary/summaryManager.js.map +1 -1
- package/internal.d.ts +1 -1
- package/legacy.d.ts +1 -1
- package/lib/containerCompatibility.d.ts +1 -1
- package/lib/containerCompatibility.d.ts.map +1 -1
- package/lib/containerCompatibility.js.map +1 -1
- package/lib/containerRuntime.d.ts +36 -9
- package/lib/containerRuntime.d.ts.map +1 -1
- package/lib/containerRuntime.js +97 -55
- package/lib/containerRuntime.js.map +1 -1
- package/lib/gc/garbageCollection.d.ts +1 -0
- package/lib/gc/garbageCollection.d.ts.map +1 -1
- package/lib/gc/garbageCollection.js +3 -8
- package/lib/gc/garbageCollection.js.map +1 -1
- package/lib/gc/gcDefinitions.d.ts +4 -0
- package/lib/gc/gcDefinitions.d.ts.map +1 -1
- package/lib/gc/gcDefinitions.js.map +1 -1
- package/lib/index.d.ts +1 -1
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +1 -1
- package/lib/index.js.map +1 -1
- package/lib/legacy.d.ts +1 -1
- package/lib/opLifecycle/batchManager.d.ts.map +1 -1
- package/lib/opLifecycle/batchManager.js +2 -1
- package/lib/opLifecycle/batchManager.js.map +1 -1
- package/lib/opLifecycle/index.d.ts +1 -1
- package/lib/opLifecycle/index.d.ts.map +1 -1
- package/lib/opLifecycle/index.js +1 -1
- package/lib/opLifecycle/index.js.map +1 -1
- package/lib/opLifecycle/opGroupingManager.d.ts +6 -0
- package/lib/opLifecycle/opGroupingManager.d.ts.map +1 -1
- package/lib/opLifecycle/opGroupingManager.js +10 -1
- package/lib/opLifecycle/opGroupingManager.js.map +1 -1
- package/lib/opLifecycle/opSerialization.d.ts +3 -1
- package/lib/opLifecycle/opSerialization.d.ts.map +1 -1
- package/lib/opLifecycle/opSerialization.js +11 -9
- package/lib/opLifecycle/opSerialization.js.map +1 -1
- package/lib/opLifecycle/outbox.d.ts +0 -6
- package/lib/opLifecycle/outbox.d.ts.map +1 -1
- package/lib/opLifecycle/outbox.js +2 -9
- package/lib/opLifecycle/outbox.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/pendingStateManager.d.ts +7 -3
- package/lib/pendingStateManager.d.ts.map +1 -1
- package/lib/pendingStateManager.js +19 -7
- package/lib/pendingStateManager.js.map +1 -1
- package/lib/public.d.ts +1 -1
- package/lib/runtimeLayerCompatState.d.ts +1 -1
- package/lib/summary/documentSchema.d.ts +9 -3
- package/lib/summary/documentSchema.d.ts.map +1 -1
- package/lib/summary/documentSchema.js +19 -3
- package/lib/summary/documentSchema.js.map +1 -1
- package/lib/summary/orderedClientElection.js +2 -2
- package/lib/summary/orderedClientElection.js.map +1 -1
- package/lib/summary/summaryManager.d.ts +1 -0
- package/lib/summary/summaryManager.d.ts.map +1 -1
- package/lib/summary/summaryManager.js +9 -0
- package/lib/summary/summaryManager.js.map +1 -1
- package/package.json +27 -23
- package/src/containerCompatibility.ts +2 -0
- package/src/containerRuntime.ts +144 -66
- package/src/gc/garbageCollection.ts +4 -9
- package/src/gc/gcDefinitions.ts +4 -0
- package/src/index.ts +1 -0
- package/src/opLifecycle/batchManager.ts +2 -1
- package/src/opLifecycle/index.ts +1 -0
- package/src/opLifecycle/opGroupingManager.ts +11 -1
- package/src/opLifecycle/opSerialization.ts +14 -12
- package/src/opLifecycle/outbox.ts +2 -17
- package/src/packageVersion.ts +1 -1
- package/src/pendingStateManager.ts +27 -11
- package/src/summary/documentSchema.ts +25 -2
- package/src/summary/orderedClientElection.ts +2 -2
- package/src/summary/summaryManager.ts +11 -0
package/dist/containerRuntime.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Licensed under the MIT License.
|
|
5
5
|
*/
|
|
6
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
-
exports.isContainerMessageDirtyable = exports.ContainerRuntime = exports.loadContainerRuntime = exports.getSingleUseLegacyLogCallback = exports.makeLegacySendBatchFn = exports.getDeviceSpec = exports.agentSchedulerId = exports.isUnpackedRuntimeMessage = exports.defaultPendingOpsRetryDelayMs = exports.defaultPendingOpsWaitTimeoutMs = exports.defaultRuntimeHeaderData = exports.InactiveResponseHeaderKey = exports.TombstoneResponseHeaderKey = exports.DeletedResponseHeaderKey = void 0;
|
|
7
|
+
exports.isContainerMessageDirtyable = exports.ContainerRuntime = exports.loadContainerRuntimeAlpha = exports.loadContainerRuntime = exports.getSingleUseLegacyLogCallback = exports.makeLegacySendBatchFn = exports.getDeviceSpec = exports.agentSchedulerId = exports.isUnpackedRuntimeMessage = exports.defaultPendingOpsRetryDelayMs = exports.defaultPendingOpsWaitTimeoutMs = exports.defaultRuntimeHeaderData = exports.InactiveResponseHeaderKey = exports.TombstoneResponseHeaderKey = exports.DeletedResponseHeaderKey = void 0;
|
|
8
8
|
const client_utils_1 = require("@fluid-internal/client-utils");
|
|
9
9
|
const container_definitions_1 = require("@fluidframework/container-definitions");
|
|
10
10
|
const internal_1 = require("@fluidframework/container-definitions/internal");
|
|
@@ -105,6 +105,15 @@ const maxConsecutiveReconnectsKey = "Fluid.ContainerRuntime.MaxConsecutiveReconn
|
|
|
105
105
|
// - we do not stringify final op, thus we do not know how much escaping will be added.
|
|
106
106
|
const defaultMaxBatchSizeInBytes = 700 * 1024;
|
|
107
107
|
const defaultChunkSizeInBytes = 204800;
|
|
108
|
+
/**
|
|
109
|
+
* Default maximum ops per staging-mode batch before automatic flush scheduling resumes.
|
|
110
|
+
*
|
|
111
|
+
* Chosen based on production telemetry: copy-paste operations routinely produce batches
|
|
112
|
+
* of 1000+ ops (435K instances over 30 days), and receivers on modern Fluid versions
|
|
113
|
+
* handle them without issues. Uses {@link largeBatchThreshold} to stay aligned with
|
|
114
|
+
* the existing "large batch" telemetry threshold ({@link OpGroupingManager}).
|
|
115
|
+
*/
|
|
116
|
+
const defaultStagingModeAutoFlushThreshold = index_js_3.largeBatchThreshold;
|
|
108
117
|
/**
|
|
109
118
|
* The default time to wait for pending ops to be processed during summarization
|
|
110
119
|
*/
|
|
@@ -206,6 +215,22 @@ async function loadContainerRuntime(params) {
|
|
|
206
215
|
return ContainerRuntime.loadRuntime(params);
|
|
207
216
|
}
|
|
208
217
|
exports.loadContainerRuntime = loadContainerRuntime;
|
|
218
|
+
/**
|
|
219
|
+
* Alpha variant of {@link loadContainerRuntime} that returns the runtime in an
|
|
220
|
+
* extendable object, allowing additional properties to be added in the future.
|
|
221
|
+
*
|
|
222
|
+
* @param params - An object which specifies all required and optional params necessary to instantiate a runtime.
|
|
223
|
+
* @returns An object containing the runtime.
|
|
224
|
+
*
|
|
225
|
+
* @legacy @alpha
|
|
226
|
+
*/
|
|
227
|
+
async function loadContainerRuntimeAlpha(params) {
|
|
228
|
+
return ContainerRuntime.loadRuntime2({
|
|
229
|
+
...params,
|
|
230
|
+
registry: new dataStoreRegistry_js_1.FluidDataStoreRegistry(params.registryEntries),
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
exports.loadContainerRuntimeAlpha = loadContainerRuntimeAlpha;
|
|
209
234
|
const defaultMaxConsecutiveReconnects = 7;
|
|
210
235
|
/**
|
|
211
236
|
* These are the ONLY message types that are allowed to be submitted while in staging mode
|
|
@@ -245,13 +270,14 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
245
270
|
return ContainerRuntime.loadRuntime2({
|
|
246
271
|
...params,
|
|
247
272
|
registry: new dataStoreRegistry_js_1.FluidDataStoreRegistry(params.registryEntries),
|
|
248
|
-
});
|
|
273
|
+
}).then((r) => r.runtime);
|
|
249
274
|
}
|
|
250
275
|
/**
|
|
251
|
-
* Load the stores from a snapshot and returns the runtime.
|
|
276
|
+
* Load the stores from a snapshot and returns an object containing the runtime.
|
|
252
277
|
* @remarks
|
|
253
278
|
* Same as {@link ContainerRuntime.loadRuntime},
|
|
254
279
|
* but with `registry` instead of `registryEntries` and more `runtimeOptions`.
|
|
280
|
+
* Returns `{ runtime }` to allow future extensions (e.g. staging mode controls).
|
|
255
281
|
*/
|
|
256
282
|
static async loadRuntime2(params) {
|
|
257
283
|
const { context, registry, existing, requestHandler, provideEntryPoint, runtimeOptions = {}, containerScope = {}, containerRuntimeCtor = ContainerRuntime, minVersionForCollab = internal_7.defaultMinVersionForCollab, } = params;
|
|
@@ -288,6 +314,8 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
288
314
|
loadSequenceNumberVerification: "close",
|
|
289
315
|
maxBatchSizeInBytes: defaultMaxBatchSizeInBytes,
|
|
290
316
|
chunkSizeInBytes: defaultChunkSizeInBytes,
|
|
317
|
+
stagingModeAutoFlushThreshold: defaultStagingModeAutoFlushThreshold,
|
|
318
|
+
disableSchemaUpgrade: false,
|
|
291
319
|
};
|
|
292
320
|
const defaultConfigs = {
|
|
293
321
|
...defaultsAffectingDocSchema,
|
|
@@ -301,7 +329,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
301
329
|
// is enabled via runtimeOptions, we will throw an error later.
|
|
302
330
|
compressionOptions = enableGroupedBatching === false
|
|
303
331
|
? compressionDefinitions_js_1.disabledCompressionConfig
|
|
304
|
-
: defaultConfigs.compressionOptions, createBlobPayloadPending = defaultConfigs.createBlobPayloadPending, } = runtimeOptions;
|
|
332
|
+
: defaultConfigs.compressionOptions, createBlobPayloadPending = defaultConfigs.createBlobPayloadPending, stagingModeAutoFlushThreshold = defaultConfigs.stagingModeAutoFlushThreshold, disableSchemaUpgrade = defaultConfigs.disableSchemaUpgrade, } = runtimeOptions;
|
|
305
333
|
// If explicitSchemaControl is off, ensure that options which require explicitSchemaControl are not enabled.
|
|
306
334
|
if (!explicitSchemaControl) {
|
|
307
335
|
const disallowedKeys = Object.keys(runtimeOptions).filter((key) => containerCompatibility_js_1.runtimeOptionKeysThatRequireExplicitSchemaControl.includes(key) && runtimeOptions[key] !== undefined);
|
|
@@ -408,6 +436,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
408
436
|
else {
|
|
409
437
|
idCompressorMode = desiredIdCompressorMode;
|
|
410
438
|
}
|
|
439
|
+
// eslint-disable-next-line import-x/no-deprecated -- Will be undeprecated in 2.100.0 when it becomes an internal API
|
|
411
440
|
const createIdCompressorFn = () => {
|
|
412
441
|
/**
|
|
413
442
|
* Because the IdCompressor emits so much telemetry, this function is used to sample
|
|
@@ -444,7 +473,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
444
473
|
disallowedVersions: [],
|
|
445
474
|
}, (schema) => {
|
|
446
475
|
runtime.onSchemaChange(schema);
|
|
447
|
-
}, { minVersionForCollab }, logger);
|
|
476
|
+
}, { minVersionForCollab }, logger, disableSchemaUpgrade);
|
|
448
477
|
// If the minVersionForCollab for this client is greater than the existing one, we should use that one going forward.
|
|
449
478
|
const existingMinVersionForCollab = documentSchemaController.sessionSchema.info.minVersionForCollab;
|
|
450
479
|
const updatedMinVersionForCollab = existingMinVersionForCollab === undefined ||
|
|
@@ -468,6 +497,8 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
468
497
|
enableGroupedBatching,
|
|
469
498
|
explicitSchemaControl,
|
|
470
499
|
createBlobPayloadPending,
|
|
500
|
+
stagingModeAutoFlushThreshold,
|
|
501
|
+
disableSchemaUpgrade,
|
|
471
502
|
};
|
|
472
503
|
(0, internal_7.validateMinimumVersionForCollab)(updatedMinVersionForCollab);
|
|
473
504
|
const runtime = new containerRuntimeCtor(context, registry, metadata, electedSummarizerData, chunks ?? [], aliases ?? [], internalRuntimeOptions, containerScope, logger, existing, blobManagerLoadInfo, context.storage, createIdCompressorFn, documentSchemaController, featureGatesForTelemetry, provideEntryPoint, updatedMinVersionForCollab, requestHandler, undefined, // summaryConfiguration
|
|
@@ -478,7 +509,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
478
509
|
// Apply stashed ops with a reference sequence number equal to the sequence number of the snapshot,
|
|
479
510
|
// or zero. This must be done before Container replays saved ops.
|
|
480
511
|
await runtime.pendingStateManager.applyStashedOpsAt(runtimeSequenceNumber ?? 0);
|
|
481
|
-
return runtime;
|
|
512
|
+
return { runtime };
|
|
482
513
|
}
|
|
483
514
|
get clientId() {
|
|
484
515
|
return this._getClientId();
|
|
@@ -517,6 +548,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
517
548
|
/**
|
|
518
549
|
* {@inheritDoc @fluidframework/runtime-definitions#IContainerRuntimeBase.idCompressor}
|
|
519
550
|
*/
|
|
551
|
+
// eslint-disable-next-line import-x/no-deprecated -- Will be undeprecated in 2.100.0 when it becomes an internal API
|
|
520
552
|
get idCompressor() {
|
|
521
553
|
// Expose ID Compressor only if it's On from the start.
|
|
522
554
|
// If container uses delayed mode, then we can only expose generateDocumentUniqueId() and nothing else.
|
|
@@ -595,7 +627,9 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
595
627
|
/***/
|
|
596
628
|
constructor(context, registry, metadata, electedSummarizerData, chunks, dataStoreAliasMap, runtimeOptions, containerScope,
|
|
597
629
|
// Create a custom ITelemetryBaseLogger to output telemetry events.
|
|
598
|
-
baseLogger, existing, blobManagerLoadInfo, _storage,
|
|
630
|
+
baseLogger, existing, blobManagerLoadInfo, _storage,
|
|
631
|
+
// eslint-disable-next-line import-x/no-deprecated -- Will be undeprecated in 2.100.0 when it becomes an internal API
|
|
632
|
+
createIdCompressorFn, documentsSchemaController, featureGatesForTelemetry, provideEntryPoint, minVersionForCollab, requestHandler,
|
|
599
633
|
// // eslint-disable-next-line unicorn/no-object-as-default-parameter
|
|
600
634
|
summaryConfiguration = {
|
|
601
635
|
// the defaults
|
|
@@ -652,17 +686,28 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
652
686
|
// Make sure Outbox is empty before entering staging mode,
|
|
653
687
|
// since we mark whole batches as "staged" or not to indicate whether to submit them.
|
|
654
688
|
this.flush();
|
|
655
|
-
const exitStagingMode = (discardOrCommit) => {
|
|
689
|
+
const exitStagingMode = (discardOrCommit, exitMethod) => {
|
|
656
690
|
try {
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
691
|
+
internal_8.PerformanceEvent.timedExec(this.mc.logger, {
|
|
692
|
+
eventName: `ExitStagingMode_${exitMethod}`,
|
|
693
|
+
}, (event) => {
|
|
694
|
+
// Final flush of any last staged changes
|
|
695
|
+
// NOTE: We can't use this.flush() here, because orderSequentially uses StagingMode and in the rollback case we'll hit assert 0x24c
|
|
696
|
+
this.outbox.flush();
|
|
697
|
+
this.stageControls = undefined;
|
|
698
|
+
// During Staging Mode, we avoid submitting any ID Allocation ops (apart from resubmitting pre-staging ops).
|
|
699
|
+
// Now that we've exited, we need to submit an ID Allocation op for any IDs that were generated while in Staging Mode.
|
|
700
|
+
this.submitIdAllocationOpIfNeeded({ staged: false });
|
|
701
|
+
const batchInfos = discardOrCommit();
|
|
702
|
+
event.reportProgress({
|
|
703
|
+
details: {
|
|
704
|
+
autoFlushThreshold: this.stagingModeAutoFlushThreshold,
|
|
705
|
+
batches: batchInfos.length,
|
|
706
|
+
batchesAtOrOverThreshold: batchInfos.filter((b) => b.length >= this.stagingModeAutoFlushThreshold).length,
|
|
707
|
+
},
|
|
708
|
+
});
|
|
709
|
+
this.channelCollection.notifyStagingMode(false);
|
|
710
|
+
});
|
|
666
711
|
}
|
|
667
712
|
catch (error) {
|
|
668
713
|
const normalizedError = (0, internal_8.normalizeError)(error);
|
|
@@ -673,21 +718,22 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
673
718
|
const stageControls = {
|
|
674
719
|
discardChanges: () => exitStagingMode(() => {
|
|
675
720
|
// Pop all staged batches from the PSM and roll them back in LIFO order
|
|
676
|
-
this.pendingStateManager.popStagedBatches(({ runtimeOp, localOpMetadata }) => {
|
|
721
|
+
const batchInfos = this.pendingStateManager.popStagedBatches(({ runtimeOp, localOpMetadata }) => {
|
|
677
722
|
this.rollbackStagedChange(runtimeOp, localOpMetadata);
|
|
678
723
|
});
|
|
679
724
|
this.updateDocumentDirtyState();
|
|
680
|
-
|
|
725
|
+
return batchInfos;
|
|
726
|
+
}, "discard"),
|
|
681
727
|
commitChanges: (options) => {
|
|
682
728
|
const { squash } = { ...defaultStagingCommitOptions, ...options };
|
|
683
729
|
exitStagingMode(() => {
|
|
684
730
|
// Replay all staged batches in typical FIFO order.
|
|
685
731
|
// We'll be out of staging mode so they'll be sent to the service finally.
|
|
686
|
-
this.pendingStateManager.replayPendingStates({
|
|
732
|
+
return this.pendingStateManager.replayPendingStates({
|
|
687
733
|
committingStagedBatches: true,
|
|
688
734
|
squash,
|
|
689
735
|
});
|
|
690
|
-
});
|
|
736
|
+
}, "commit");
|
|
691
737
|
},
|
|
692
738
|
};
|
|
693
739
|
this.stageControls = stageControls;
|
|
@@ -870,14 +916,6 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
870
916
|
? this.getConnectionState() === internal_1.ConnectionState.Connected ||
|
|
871
917
|
this.getConnectionState() === internal_1.ConnectionState.CatchingUp
|
|
872
918
|
: undefined;
|
|
873
|
-
this.mc.logger.sendTelemetryEvent({
|
|
874
|
-
eventName: "GCFeatureMatrix",
|
|
875
|
-
metadataValue: JSON.stringify(metadata?.gcFeatureMatrix),
|
|
876
|
-
inputs: JSON.stringify({
|
|
877
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
878
|
-
gcOptions_gcGeneration: runtimeOptions.gcOptions[index_js_2.gcGenerationOptionName],
|
|
879
|
-
}),
|
|
880
|
-
});
|
|
881
919
|
this.telemetryDocumentId = metadata?.telemetryDocumentId ?? (0, uuid_1.v4)();
|
|
882
920
|
const opGroupingManager = new index_js_3.OpGroupingManager({
|
|
883
921
|
groupedBatchingEnabled: this.groupedBatchingEnabled,
|
|
@@ -925,6 +963,10 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
925
963
|
this.closeFn(error);
|
|
926
964
|
throw error;
|
|
927
965
|
}
|
|
966
|
+
this.stagingModeAutoFlushThreshold =
|
|
967
|
+
this.mc.config.getNumber("Fluid.ContainerRuntime.StagingModeAutoFlushThreshold") ??
|
|
968
|
+
runtimeOptions.stagingModeAutoFlushThreshold ??
|
|
969
|
+
defaultStagingModeAutoFlushThreshold;
|
|
928
970
|
this.batchIdTrackingEnabled =
|
|
929
971
|
this.mc.config.getBoolean("Fluid.Container.enableOfflineFull") ??
|
|
930
972
|
this.mc.config.getBoolean("Fluid.ContainerRuntime.enableBatchIdTracking") ??
|
|
@@ -1034,9 +1076,6 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
1034
1076
|
this.deltaScheduler = new deltaScheduler_js_1.DeltaScheduler(this.innerDeltaManager, this, (0, internal_8.createChildLogger)({ logger: this.baseLogger, namespace: "DeltaScheduler" }));
|
|
1035
1077
|
this.inboundBatchAggregator = new inboundBatchAggregator_js_1.InboundBatchAggregator(this.innerDeltaManager, () => this.clientId, (0, internal_8.createChildLogger)({ logger: this.baseLogger, namespace: "InboundBatchAggregator" }));
|
|
1036
1078
|
const legacySendBatchFn = (0, exports.makeLegacySendBatchFn)(submitFn, this.innerDeltaManager);
|
|
1037
|
-
this.skipSafetyFlushDuringProcessStack =
|
|
1038
|
-
// Keep the old flag name even though we renamed the class member (it shipped in 2.31.0)
|
|
1039
|
-
this.mc.config.getBoolean("Fluid.ContainerRuntime.DisableFlushBeforeProcess") === true;
|
|
1040
1079
|
this.outbox = new index_js_3.Outbox({
|
|
1041
1080
|
shouldSend: () => this.shouldSendOps(),
|
|
1042
1081
|
pendingStateManager: this.pendingStateManager,
|
|
@@ -1047,8 +1086,6 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
1047
1086
|
config: {
|
|
1048
1087
|
compressionOptions,
|
|
1049
1088
|
maxBatchSizeInBytes: runtimeOptions.maxBatchSizeInBytes,
|
|
1050
|
-
// If we disable flush before process, we must be ready to flush partial batches
|
|
1051
|
-
flushPartialBatches: this.skipSafetyFlushDuringProcessStack,
|
|
1052
1089
|
},
|
|
1053
1090
|
logger: this.mc.logger,
|
|
1054
1091
|
groupingManager: opGroupingManager,
|
|
@@ -1092,14 +1129,12 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
1092
1129
|
// We haven't emitted dirty/saved yet, but this is the baseline so we know to emit when it changes
|
|
1093
1130
|
this.lastEmittedDirty = this.computeCurrentDirtyState();
|
|
1094
1131
|
context.updateDirtyContainerState(this.lastEmittedDirty);
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
this.deltaManager.on("op", () => this.flush());
|
|
1102
|
-
}
|
|
1132
|
+
// Reference Sequence Number may have just changed, and it must be consistent across a batch,
|
|
1133
|
+
// so we should flush now to clear the way for the next ops.
|
|
1134
|
+
// NOTE: This will be redundant whenever CR.process was called for the op (since we flush there too) -
|
|
1135
|
+
// But we need this coverage for old loaders that don't call ContainerRuntime.process for non-runtime messages.
|
|
1136
|
+
// (We have to call flush _before_ processing a runtime op, but after is ok for non-runtime op)
|
|
1137
|
+
this.deltaManager.on("op", () => this.flush());
|
|
1103
1138
|
// logging hardware telemetry
|
|
1104
1139
|
this.baseLogger.send({
|
|
1105
1140
|
category: "generic",
|
|
@@ -1113,7 +1148,9 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
1113
1148
|
summaryNumber: loadSummaryNumber,
|
|
1114
1149
|
summaryFormatVersion: metadata?.summaryFormatVersion,
|
|
1115
1150
|
disableIsolatedChannels: metadata?.disableIsolatedChannels,
|
|
1151
|
+
// This is useful even for interactive clients since they track unreferenced nodes and log errors.
|
|
1116
1152
|
gcVersion: metadata?.gcFeature,
|
|
1153
|
+
gcConfigs: this.garbageCollector.serializedConfigs,
|
|
1117
1154
|
options: JSON.stringify(runtimeOptions),
|
|
1118
1155
|
idCompressorModeMetadata: metadata?.documentSchema?.runtime?.idCompressorMode,
|
|
1119
1156
|
idCompressorMode: this.sessionSchema.idCompressorMode,
|
|
@@ -1121,7 +1158,6 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
1121
1158
|
featureGates: JSON.stringify({
|
|
1122
1159
|
...featureGatesForTelemetry,
|
|
1123
1160
|
closeSummarizerDelayOverride,
|
|
1124
|
-
disableFlushBeforeProcess: this.skipSafetyFlushDuringProcessStack,
|
|
1125
1161
|
}),
|
|
1126
1162
|
telemetryDocumentId: this.telemetryDocumentId,
|
|
1127
1163
|
groupedBatchingEnabled: this.groupedBatchingEnabled,
|
|
@@ -1578,12 +1614,10 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
1578
1614
|
(0, internal_2.assert)(this.emitDirtyDocumentEvent, 0x127 /* "dirty document event not set on replay" */);
|
|
1579
1615
|
this.emitDirtyDocumentEvent = false;
|
|
1580
1616
|
try {
|
|
1581
|
-
// Any ID Allocation ops that failed to submit
|
|
1582
|
-
// the
|
|
1583
|
-
//
|
|
1584
|
-
|
|
1585
|
-
this.submitIdAllocationOpIfNeeded({ resubmitOutstandingRanges: true, staged: false });
|
|
1586
|
-
this.scheduleFlush();
|
|
1617
|
+
// Any ID Allocation ops that failed to submit need to have their ranges included
|
|
1618
|
+
// in the next allocation op. Reset the compressor's unfinalized range cursor so that the next
|
|
1619
|
+
// call to takeNextCreationRange (during replay) will include those unfinalized ranges.
|
|
1620
|
+
this._idCompressor?.resetUnfinalizedCreationRange();
|
|
1587
1621
|
// replay the ops
|
|
1588
1622
|
this.pendingStateManager.replayPendingStates();
|
|
1589
1623
|
}
|
|
@@ -1804,10 +1838,8 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
1804
1838
|
// spread operator above ensure we make a shallow copy of message, as the processing flow will modify it.
|
|
1805
1839
|
// There might be multiple container instances receiving the same message.
|
|
1806
1840
|
this.verifyNotClosed();
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
this.flush();
|
|
1810
|
-
}
|
|
1841
|
+
// Reference Sequence Number may be about to change, and it must be consistent across a batch, so flush now
|
|
1842
|
+
this.flush();
|
|
1811
1843
|
this.ensureNoDataModelChanges(() => {
|
|
1812
1844
|
this.processInboundMessageOrBatch(messageCopy, local);
|
|
1813
1845
|
});
|
|
@@ -3038,6 +3070,17 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
3038
3070
|
this.updateDocumentDirtyState();
|
|
3039
3071
|
}
|
|
3040
3072
|
scheduleFlush() {
|
|
3073
|
+
// During staging mode, suppress automatic flush scheduling until the main batch
|
|
3074
|
+
// reaches or exceeds the threshold.
|
|
3075
|
+
// Incoming ops still break the batch via direct this.flush() calls elsewhere
|
|
3076
|
+
// (deltaManager "op" handler, process(), connection changes, getPendingLocalState,
|
|
3077
|
+
// exitStagingMode). Those all bypass scheduleFlush(), so they're unaffected by this check.
|
|
3078
|
+
// Additionally, outbox.maybeFlushPartialBatch() (called on every submit) detects
|
|
3079
|
+
// sequence number changes and throws if unexpected changes are detected.
|
|
3080
|
+
if (this.inStagingMode &&
|
|
3081
|
+
this.outbox.mainBatchMessageCount < this.stagingModeAutoFlushThreshold) {
|
|
3082
|
+
return;
|
|
3083
|
+
}
|
|
3041
3084
|
if (this.flushScheduled) {
|
|
3042
3085
|
return;
|
|
3043
3086
|
}
|
|
@@ -3332,7 +3375,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
3332
3375
|
return internal_8.PerformanceEvent.timedExec(this.mc.logger, {
|
|
3333
3376
|
eventName: "getPendingLocalState",
|
|
3334
3377
|
}, (event) => {
|
|
3335
|
-
const pending = this.pendingStateManager.getLocalState(props?.snapshotSequenceNumber);
|
|
3378
|
+
const { pending } = this.pendingStateManager.getLocalState(props?.snapshotSequenceNumber);
|
|
3336
3379
|
const sessionExpiryTimerStarted = props?.sessionExpiryTimerStarted ?? this.garbageCollector.sessionExpiryTimerStarted;
|
|
3337
3380
|
const pendingIdCompressorState = this._idCompressor?.serialize(true);
|
|
3338
3381
|
const pendingAttachmentBlobs = this.blobManager.getPendingBlobs();
|