@fluidframework/container-runtime 2.0.0-internal.5.1.0 → 2.0.0-internal.5.2.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 +16 -0
- package/dist/containerRuntime.d.ts +22 -0
- package/dist/containerRuntime.d.ts.map +1 -1
- package/dist/containerRuntime.js +54 -10
- package/dist/containerRuntime.js.map +1 -1
- package/dist/dataStoreContext.d.ts +1 -2
- package/dist/dataStoreContext.d.ts.map +1 -1
- package/dist/dataStoreContext.js.map +1 -1
- package/dist/dataStoreContexts.d.ts +2 -1
- package/dist/dataStoreContexts.d.ts.map +1 -1
- package/dist/dataStoreContexts.js.map +1 -1
- package/dist/dataStores.d.ts +2 -1
- package/dist/dataStores.d.ts.map +1 -1
- package/dist/dataStores.js.map +1 -1
- package/dist/gc/gcDefinitions.d.ts +0 -1
- 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.map +1 -1
- package/dist/opLifecycle/batchManager.d.ts +2 -1
- package/dist/opLifecycle/batchManager.d.ts.map +1 -1
- package/dist/opLifecycle/batchManager.js +5 -1
- package/dist/opLifecycle/batchManager.js.map +1 -1
- package/dist/opLifecycle/definitions.d.ts +11 -0
- package/dist/opLifecycle/definitions.d.ts.map +1 -1
- package/dist/opLifecycle/definitions.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/outbox.d.ts +29 -2
- package/dist/opLifecycle/outbox.d.ts.map +1 -1
- package/dist/opLifecycle/outbox.js +87 -19
- 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 +8 -3
- package/dist/pendingStateManager.d.ts.map +1 -1
- package/dist/pendingStateManager.js +23 -16
- package/dist/pendingStateManager.js.map +1 -1
- package/dist/summary/index.d.ts +2 -2
- package/dist/summary/index.d.ts.map +1 -1
- package/dist/summary/index.js +2 -1
- package/dist/summary/index.js.map +1 -1
- package/dist/summary/runningSummarizer.d.ts +1 -1
- package/dist/summary/runningSummarizer.d.ts.map +1 -1
- package/dist/summary/runningSummarizer.js.map +1 -1
- package/dist/summary/summarizerNode/index.d.ts +1 -1
- package/dist/summary/summarizerNode/index.d.ts.map +1 -1
- package/dist/summary/summarizerNode/index.js.map +1 -1
- package/dist/summary/summarizerNode/summarizerNode.d.ts +32 -6
- package/dist/summary/summarizerNode/summarizerNode.d.ts.map +1 -1
- package/dist/summary/summarizerNode/summarizerNode.js +90 -22
- package/dist/summary/summarizerNode/summarizerNode.js.map +1 -1
- package/dist/summary/summarizerNode/summarizerNodeUtils.d.ts +22 -2
- package/dist/summary/summarizerNode/summarizerNodeUtils.d.ts.map +1 -1
- package/dist/summary/summarizerNode/summarizerNodeUtils.js.map +1 -1
- package/dist/summary/summarizerNode/summarizerNodeWithGc.d.ts +17 -2
- package/dist/summary/summarizerNode/summarizerNodeWithGc.d.ts.map +1 -1
- package/dist/summary/summarizerNode/summarizerNodeWithGc.js +56 -20
- package/dist/summary/summarizerNode/summarizerNodeWithGc.js.map +1 -1
- package/dist/summary/summarizerTypes.d.ts +7 -1
- package/dist/summary/summarizerTypes.d.ts.map +1 -1
- package/dist/summary/summarizerTypes.js.map +1 -1
- package/dist/summary/summaryCollection.d.ts +2 -1
- package/dist/summary/summaryCollection.d.ts.map +1 -1
- package/dist/summary/summaryCollection.js.map +1 -1
- package/dist/summary/summaryFormat.d.ts +1 -0
- package/dist/summary/summaryFormat.d.ts.map +1 -1
- package/dist/summary/summaryFormat.js +2 -1
- package/dist/summary/summaryFormat.js.map +1 -1
- package/dist/summary/summaryGenerator.d.ts +13 -4
- package/dist/summary/summaryGenerator.d.ts.map +1 -1
- package/dist/summary/summaryGenerator.js +22 -8
- package/dist/summary/summaryGenerator.js.map +1 -1
- package/dist/summary/summaryManager.d.ts +2 -1
- package/dist/summary/summaryManager.d.ts.map +1 -1
- package/dist/summary/summaryManager.js.map +1 -1
- package/lib/containerRuntime.d.ts +22 -0
- package/lib/containerRuntime.d.ts.map +1 -1
- package/lib/containerRuntime.js +57 -13
- package/lib/containerRuntime.js.map +1 -1
- package/lib/dataStoreContext.d.ts +1 -2
- package/lib/dataStoreContext.d.ts.map +1 -1
- package/lib/dataStoreContext.js.map +1 -1
- package/lib/dataStoreContexts.d.ts +2 -1
- package/lib/dataStoreContexts.d.ts.map +1 -1
- package/lib/dataStoreContexts.js.map +1 -1
- package/lib/dataStores.d.ts +2 -1
- package/lib/dataStores.d.ts.map +1 -1
- package/lib/dataStores.js.map +1 -1
- package/lib/gc/gcDefinitions.d.ts +0 -1
- 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.map +1 -1
- package/lib/opLifecycle/batchManager.d.ts +2 -1
- package/lib/opLifecycle/batchManager.d.ts.map +1 -1
- package/lib/opLifecycle/batchManager.js +5 -1
- package/lib/opLifecycle/batchManager.js.map +1 -1
- package/lib/opLifecycle/definitions.d.ts +11 -0
- package/lib/opLifecycle/definitions.d.ts.map +1 -1
- package/lib/opLifecycle/definitions.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/outbox.d.ts +29 -2
- package/lib/opLifecycle/outbox.d.ts.map +1 -1
- package/lib/opLifecycle/outbox.js +85 -18
- 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 +8 -3
- package/lib/pendingStateManager.d.ts.map +1 -1
- package/lib/pendingStateManager.js +23 -16
- package/lib/pendingStateManager.js.map +1 -1
- package/lib/summary/index.d.ts +2 -2
- package/lib/summary/index.d.ts.map +1 -1
- package/lib/summary/index.js +1 -1
- package/lib/summary/index.js.map +1 -1
- package/lib/summary/runningSummarizer.d.ts +1 -1
- package/lib/summary/runningSummarizer.d.ts.map +1 -1
- package/lib/summary/runningSummarizer.js.map +1 -1
- package/lib/summary/summarizerNode/index.d.ts +1 -1
- package/lib/summary/summarizerNode/index.d.ts.map +1 -1
- package/lib/summary/summarizerNode/index.js.map +1 -1
- package/lib/summary/summarizerNode/summarizerNode.d.ts +32 -6
- package/lib/summary/summarizerNode/summarizerNode.d.ts.map +1 -1
- package/lib/summary/summarizerNode/summarizerNode.js +90 -22
- package/lib/summary/summarizerNode/summarizerNode.js.map +1 -1
- package/lib/summary/summarizerNode/summarizerNodeUtils.d.ts +22 -2
- package/lib/summary/summarizerNode/summarizerNodeUtils.d.ts.map +1 -1
- package/lib/summary/summarizerNode/summarizerNodeUtils.js.map +1 -1
- package/lib/summary/summarizerNode/summarizerNodeWithGc.d.ts +17 -2
- package/lib/summary/summarizerNode/summarizerNodeWithGc.d.ts.map +1 -1
- package/lib/summary/summarizerNode/summarizerNodeWithGc.js +56 -20
- package/lib/summary/summarizerNode/summarizerNodeWithGc.js.map +1 -1
- package/lib/summary/summarizerTypes.d.ts +7 -1
- package/lib/summary/summarizerTypes.d.ts.map +1 -1
- package/lib/summary/summarizerTypes.js.map +1 -1
- package/lib/summary/summaryCollection.d.ts +2 -1
- package/lib/summary/summaryCollection.d.ts.map +1 -1
- package/lib/summary/summaryCollection.js.map +1 -1
- package/lib/summary/summaryFormat.d.ts +1 -0
- package/lib/summary/summaryFormat.d.ts.map +1 -1
- package/lib/summary/summaryFormat.js +2 -1
- package/lib/summary/summaryFormat.js.map +1 -1
- package/lib/summary/summaryGenerator.d.ts +13 -4
- package/lib/summary/summaryGenerator.d.ts.map +1 -1
- package/lib/summary/summaryGenerator.js +20 -7
- package/lib/summary/summaryGenerator.js.map +1 -1
- package/lib/summary/summaryManager.d.ts +2 -1
- package/lib/summary/summaryManager.d.ts.map +1 -1
- package/lib/summary/summaryManager.js.map +1 -1
- package/package.json +17 -17
- package/src/containerRuntime.ts +82 -14
- package/src/dataStoreContext.ts +8 -2
- package/src/dataStoreContexts.ts +2 -1
- package/src/dataStores.ts +2 -2
- package/src/gc/gcDefinitions.ts +0 -1
- package/src/index.ts +2 -0
- package/src/opLifecycle/batchManager.ts +9 -1
- package/src/opLifecycle/definitions.ts +11 -0
- package/src/opLifecycle/index.ts +1 -1
- package/src/opLifecycle/outbox.ts +107 -16
- package/src/packageVersion.ts +1 -1
- package/src/pendingStateManager.ts +38 -34
- package/src/summary/index.ts +3 -1
- package/src/summary/runningSummarizer.ts +1 -1
- package/src/summary/summarizerNode/index.ts +1 -0
- package/src/summary/summarizerNode/summarizerNode.ts +107 -25
- package/src/summary/summarizerNode/summarizerNodeUtils.ts +25 -2
- package/src/summary/summarizerNode/summarizerNodeWithGc.ts +61 -19
- package/src/summary/summarizerTypes.ts +10 -1
- package/src/summary/summaryCollection.ts +2 -1
- package/src/summary/summaryFormat.ts +5 -1
- package/src/summary/summaryGenerator.ts +31 -8
- package/src/summary/summaryManager.ts +2 -1
package/src/containerRuntime.ts
CHANGED
|
@@ -113,7 +113,11 @@ import { v4 as uuid } from "uuid";
|
|
|
113
113
|
import { ContainerFluidHandleContext } from "./containerHandleContext";
|
|
114
114
|
import { FluidDataStoreRegistry } from "./dataStoreRegistry";
|
|
115
115
|
import { ReportOpPerfTelemetry, IPerfSignalReport } from "./connectionTelemetry";
|
|
116
|
-
import {
|
|
116
|
+
import {
|
|
117
|
+
IPendingBatchMessage,
|
|
118
|
+
IPendingLocalState,
|
|
119
|
+
PendingStateManager,
|
|
120
|
+
} from "./pendingStateManager";
|
|
117
121
|
import { pkgVersion } from "./packageVersion";
|
|
118
122
|
import { BlobManager, IBlobManagerLoadInfo, IPendingBlobs } from "./blobManager";
|
|
119
123
|
import { DataStores, getSummaryForDatastores } from "./dataStores";
|
|
@@ -149,6 +153,8 @@ import {
|
|
|
149
153
|
ISummarizerRuntime,
|
|
150
154
|
IRefreshSummaryAckOptions,
|
|
151
155
|
RunWhileConnectedCoordinator,
|
|
156
|
+
IGenerateSummaryTreeResult,
|
|
157
|
+
RetriableSummaryError,
|
|
152
158
|
} from "./summary";
|
|
153
159
|
import { formExponentialFn, Throttler } from "./throttler";
|
|
154
160
|
import {
|
|
@@ -173,6 +179,7 @@ import {
|
|
|
173
179
|
OpSplitter,
|
|
174
180
|
RemoteMessageProcessor,
|
|
175
181
|
OpGroupingManager,
|
|
182
|
+
getLongStack,
|
|
176
183
|
} from "./opLifecycle";
|
|
177
184
|
import { DeltaManagerSummarizerProxy } from "./deltaManagerSummarizerProxy";
|
|
178
185
|
|
|
@@ -429,9 +436,24 @@ export interface IContainerRuntimeOptions {
|
|
|
429
436
|
* By default, the feature is disabled. If enabled from options, the `Fluid.ContainerRuntime.DisableGroupedBatching`
|
|
430
437
|
* flag can be used to disable it at runtime.
|
|
431
438
|
*
|
|
439
|
+
* For safety, {@link IContainerRuntimeOptions#enableBatchRebasing} needs to also be enabled to ensure
|
|
440
|
+
* consistency across clients.
|
|
441
|
+
*
|
|
432
442
|
* @experimental Not ready for use.
|
|
433
443
|
*/
|
|
434
444
|
readonly enableGroupedBatching?: boolean;
|
|
445
|
+
/**
|
|
446
|
+
* Configures if the runtime should rebase a batch of ops when it detects op reentrancy,
|
|
447
|
+
* when an op is created as the result of processing another op. Usually this is the case
|
|
448
|
+
* when changes are made to a DDS inside a DDS 'onChanged' event handler. This means that the
|
|
449
|
+
* reentrant op will have a different reference sequence number than the rest of the ops in
|
|
450
|
+
* the batch, resulting in a different view of the state of the data model. Therefore all ops
|
|
451
|
+
* must be resubmitted and rebased to the current reference sequence number to be in agreement
|
|
452
|
+
* about the state of the data model.
|
|
453
|
+
*
|
|
454
|
+
* @experimental Not ready for use.
|
|
455
|
+
*/
|
|
456
|
+
readonly enableBatchRebasing?: boolean;
|
|
435
457
|
}
|
|
436
458
|
|
|
437
459
|
/**
|
|
@@ -679,6 +701,7 @@ export class ContainerRuntime
|
|
|
679
701
|
chunkSizeInBytes = defaultChunkSizeInBytes,
|
|
680
702
|
enableOpReentryCheck = false,
|
|
681
703
|
enableGroupedBatching = false,
|
|
704
|
+
enableBatchRebasing = false,
|
|
682
705
|
} = runtimeOptions;
|
|
683
706
|
|
|
684
707
|
const registry = new FluidDataStoreRegistry(registryEntries);
|
|
@@ -777,6 +800,7 @@ export class ContainerRuntime
|
|
|
777
800
|
enableRuntimeIdCompressor,
|
|
778
801
|
enableOpReentryCheck,
|
|
779
802
|
enableGroupedBatching,
|
|
803
|
+
enableBatchRebasing,
|
|
780
804
|
},
|
|
781
805
|
containerScope,
|
|
782
806
|
logger,
|
|
@@ -952,6 +976,12 @@ export class ContainerRuntime
|
|
|
952
976
|
private readonly disableAttachReorder: boolean | undefined;
|
|
953
977
|
private readonly summaryStateUpdateMethod: string | undefined;
|
|
954
978
|
private readonly closeSummarizerDelayMs: number;
|
|
979
|
+
/**
|
|
980
|
+
* If true, summary generated is validate before uploading it to the server. With single commit summaries,
|
|
981
|
+
* summaries will be accepted once uploaded, so they should be validated before upload. However, this can
|
|
982
|
+
* currently be controlled via a feature flag as its a new functionality.
|
|
983
|
+
*/
|
|
984
|
+
private readonly validateSummaryBeforeUpload: boolean;
|
|
955
985
|
|
|
956
986
|
private readonly defaultTelemetrySignalSampleCount = 100;
|
|
957
987
|
private _perfSignalData: IPerfSignalReport = {
|
|
@@ -1206,7 +1236,6 @@ export class ContainerRuntime
|
|
|
1206
1236
|
getNodePackagePath: async (nodePath: string) => this.getGCNodePackagePath(nodePath),
|
|
1207
1237
|
getLastSummaryTimestampMs: () => this.messageAtLastSummary?.timestamp,
|
|
1208
1238
|
readAndParseBlob: async <T>(id: string) => readAndParse<T>(this.storage, id),
|
|
1209
|
-
getContainerDiagnosticId: () => this.context.id,
|
|
1210
1239
|
// GC runs in summarizer client and needs access to the real (non-proxy) active information. The proxy
|
|
1211
1240
|
// delta manager would always return false for summarizer client.
|
|
1212
1241
|
activeConnection: () => this.innerDeltaManager.active,
|
|
@@ -1299,7 +1328,7 @@ export class ContainerRuntime
|
|
|
1299
1328
|
close: this.closeFn,
|
|
1300
1329
|
connected: () => this.connected,
|
|
1301
1330
|
reSubmit: this.reSubmit.bind(this),
|
|
1302
|
-
|
|
1331
|
+
reSubmitBatch: this.reSubmitBatch.bind(this),
|
|
1303
1332
|
},
|
|
1304
1333
|
pendingRuntimeState?.pending,
|
|
1305
1334
|
);
|
|
@@ -1318,6 +1347,9 @@ export class ContainerRuntime
|
|
|
1318
1347
|
const disablePartialFlush = this.mc.config.getBoolean(
|
|
1319
1348
|
"Fluid.ContainerRuntime.DisablePartialFlush",
|
|
1320
1349
|
);
|
|
1350
|
+
const enableBatchRebasing =
|
|
1351
|
+
runtimeOptions.enableBatchRebasing &&
|
|
1352
|
+
this.mc.config.getBoolean("Fluid.ContainerRuntime.DisableBatchRebasing") !== true;
|
|
1321
1353
|
this.outbox = new Outbox({
|
|
1322
1354
|
shouldSend: () => this.canSendOps(),
|
|
1323
1355
|
pendingStateManager: this.pendingStateManager,
|
|
@@ -1328,6 +1360,7 @@ export class ContainerRuntime
|
|
|
1328
1360
|
compressionOptions,
|
|
1329
1361
|
maxBatchSizeInBytes: runtimeOptions.maxBatchSizeInBytes,
|
|
1330
1362
|
disablePartialFlush: disablePartialFlush === true,
|
|
1363
|
+
enableBatchRebasing,
|
|
1331
1364
|
},
|
|
1332
1365
|
logger: this.mc.logger,
|
|
1333
1366
|
groupingManager: opGroupingManager,
|
|
@@ -1335,6 +1368,9 @@ export class ContainerRuntime
|
|
|
1335
1368
|
referenceSequenceNumber: this.deltaManager.lastSequenceNumber,
|
|
1336
1369
|
clientSequenceNumber: this._processedClientSequenceNumber,
|
|
1337
1370
|
}),
|
|
1371
|
+
reSubmit: this.reSubmit.bind(this),
|
|
1372
|
+
opReentrancy: () => this.ensureNoDataModelChangesCalls > 0,
|
|
1373
|
+
closeContainer: this.closeFn,
|
|
1338
1374
|
});
|
|
1339
1375
|
|
|
1340
1376
|
this.context.quorum.on("removeMember", (clientId: string) => {
|
|
@@ -1342,12 +1378,15 @@ export class ContainerRuntime
|
|
|
1342
1378
|
});
|
|
1343
1379
|
|
|
1344
1380
|
this.summaryStateUpdateMethod = this.mc.config.getString(
|
|
1345
|
-
"Fluid.ContainerRuntime.Test.
|
|
1381
|
+
"Fluid.ContainerRuntime.Test.SummaryStateUpdateMethodV2",
|
|
1346
1382
|
);
|
|
1347
1383
|
const closeSummarizerDelayOverride = this.mc.config.getNumber(
|
|
1348
1384
|
"Fluid.ContainerRuntime.Test.CloseSummarizerDelayOverrideMs",
|
|
1349
1385
|
);
|
|
1350
1386
|
this.closeSummarizerDelayMs = closeSummarizerDelayOverride ?? defaultCloseSummarizerDelayMs;
|
|
1387
|
+
this.validateSummaryBeforeUpload =
|
|
1388
|
+
this.mc.config.getBoolean("Fluid.ContainerRuntime.Test.ValidateSummaryBeforeUpload") ??
|
|
1389
|
+
false;
|
|
1351
1390
|
|
|
1352
1391
|
this.summaryCollection = new SummaryCollection(this.deltaManager, this.logger);
|
|
1353
1392
|
|
|
@@ -1492,6 +1531,7 @@ export class ContainerRuntime
|
|
|
1492
1531
|
idCompressorEnabled: this.idCompressorEnabled,
|
|
1493
1532
|
summaryStateUpdateMethod: this.summaryStateUpdateMethod,
|
|
1494
1533
|
closeSummarizerDelayOverride,
|
|
1534
|
+
enableBatchRebasing,
|
|
1495
1535
|
}),
|
|
1496
1536
|
telemetryDocumentId: this.telemetryDocumentId,
|
|
1497
1537
|
groupedBatchingEnabled: this.groupedBatchingEnabled,
|
|
@@ -2808,7 +2848,7 @@ export class ContainerRuntime
|
|
|
2808
2848
|
summaryNumber,
|
|
2809
2849
|
...partialStats,
|
|
2810
2850
|
};
|
|
2811
|
-
const generateSummaryData = {
|
|
2851
|
+
const generateSummaryData: Omit<IGenerateSummaryTreeResult, "stage" | "error"> = {
|
|
2812
2852
|
referenceSequenceNumber: summaryRefSeqNum,
|
|
2813
2853
|
minimumSequenceNumber,
|
|
2814
2854
|
summaryTree,
|
|
@@ -2817,6 +2857,21 @@ export class ContainerRuntime
|
|
|
2817
2857
|
forcedFullTree,
|
|
2818
2858
|
} as const;
|
|
2819
2859
|
|
|
2860
|
+
// If validateSummaryBeforeUpload is true, validate that the summary generated by the summarizer nodes is
|
|
2861
|
+
// correct before this summary is uploaded.
|
|
2862
|
+
if (this.validateSummaryBeforeUpload) {
|
|
2863
|
+
const validateResult = this.summarizerNode.validateSummary();
|
|
2864
|
+
if (!validateResult.success) {
|
|
2865
|
+
const { success, ...loggingProps } = validateResult;
|
|
2866
|
+
const error = new RetriableSummaryError(
|
|
2867
|
+
validateResult.reason,
|
|
2868
|
+
validateResult.retryAfterSeconds,
|
|
2869
|
+
{ ...loggingProps },
|
|
2870
|
+
);
|
|
2871
|
+
return { stage: "base", ...generateSummaryData, error };
|
|
2872
|
+
}
|
|
2873
|
+
}
|
|
2874
|
+
|
|
2820
2875
|
continueResult = checkContinue();
|
|
2821
2876
|
if (!continueResult.continue) {
|
|
2822
2877
|
return { stage: "generate", ...generateSummaryData, error: continueResult.error };
|
|
@@ -2894,7 +2949,15 @@ export class ContainerRuntime
|
|
|
2894
2949
|
submitOpDuration: trace.trace().duration,
|
|
2895
2950
|
} as const;
|
|
2896
2951
|
|
|
2897
|
-
|
|
2952
|
+
try {
|
|
2953
|
+
// If validateSummaryBeforeUpload is false, the summary should be validated in this step.
|
|
2954
|
+
this.summarizerNode.completeSummary(
|
|
2955
|
+
handle,
|
|
2956
|
+
!this.validateSummaryBeforeUpload /* validate */,
|
|
2957
|
+
);
|
|
2958
|
+
} catch (error) {
|
|
2959
|
+
return { stage: "upload", ...uploadData, error };
|
|
2960
|
+
}
|
|
2898
2961
|
return submitData;
|
|
2899
2962
|
} finally {
|
|
2900
2963
|
// Cleanup wip summary in case of failure
|
|
@@ -3157,7 +3220,7 @@ export class ContainerRuntime
|
|
|
3157
3220
|
this.mc.logger.sendTelemetryEvent(
|
|
3158
3221
|
{ eventName: "OpReentry" },
|
|
3159
3222
|
// We need to capture the call stack in order to inspect the source of this usage pattern
|
|
3160
|
-
new UsageError(errorMessage),
|
|
3223
|
+
getLongStack(() => new UsageError(errorMessage)),
|
|
3161
3224
|
);
|
|
3162
3225
|
this.opReentryCallsToReport--;
|
|
3163
3226
|
}
|
|
@@ -3180,14 +3243,19 @@ export class ContainerRuntime
|
|
|
3180
3243
|
}
|
|
3181
3244
|
}
|
|
3182
3245
|
|
|
3183
|
-
private
|
|
3184
|
-
|
|
3185
|
-
|
|
3186
|
-
|
|
3187
|
-
|
|
3246
|
+
private reSubmitBatch(batch: IPendingBatchMessage[]) {
|
|
3247
|
+
this.orderSequentially(() => {
|
|
3248
|
+
for (const message of batch) {
|
|
3249
|
+
this.reSubmit(message);
|
|
3250
|
+
}
|
|
3251
|
+
});
|
|
3252
|
+
this.flush();
|
|
3253
|
+
}
|
|
3254
|
+
|
|
3255
|
+
private reSubmit(message: IPendingBatchMessage) {
|
|
3188
3256
|
// Need to parse from string for back-compat
|
|
3189
|
-
const { contents, type } = this.parseOpContent(content);
|
|
3190
|
-
this.reSubmitCore(type, contents, localOpMetadata, opMetadata);
|
|
3257
|
+
const { contents, type } = this.parseOpContent(message.content);
|
|
3258
|
+
this.reSubmitCore(type, contents, message.localOpMetadata, message.opMetadata);
|
|
3191
3259
|
}
|
|
3192
3260
|
|
|
3193
3261
|
/**
|
package/src/dataStoreContext.ts
CHANGED
|
@@ -3,8 +3,14 @@
|
|
|
3
3
|
* Licensed under the MIT License.
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
6
|
+
import { ITelemetryProperties } from "@fluidframework/common-definitions";
|
|
7
|
+
import {
|
|
8
|
+
IDisposable,
|
|
9
|
+
FluidObject,
|
|
10
|
+
IRequest,
|
|
11
|
+
IResponse,
|
|
12
|
+
IFluidHandle,
|
|
13
|
+
} from "@fluidframework/core-interfaces";
|
|
8
14
|
import {
|
|
9
15
|
IAudience,
|
|
10
16
|
IDeltaManager,
|
package/src/dataStoreContexts.ts
CHANGED
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
* Licensed under the MIT License.
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import {
|
|
6
|
+
import { ITelemetryBaseLogger } from "@fluidframework/common-definitions";
|
|
7
|
+
import { IDisposable } from "@fluidframework/core-interfaces";
|
|
7
8
|
import { assert, Deferred, Lazy } from "@fluidframework/common-utils";
|
|
8
9
|
import { ChildLogger, ITelemetryLoggerExt } from "@fluidframework/telemetry-utils";
|
|
9
10
|
import { FluidDataStoreContext, LocalFluidDataStoreContext } from "./dataStoreContext";
|
package/src/dataStores.ts
CHANGED
|
@@ -3,12 +3,12 @@
|
|
|
3
3
|
* Licensed under the MIT License.
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import { ITelemetryBaseLogger
|
|
6
|
+
import { ITelemetryBaseLogger } from "@fluidframework/common-definitions";
|
|
7
7
|
import {
|
|
8
8
|
DataCorruptionError,
|
|
9
9
|
extractSafePropertiesFromMessage,
|
|
10
10
|
} from "@fluidframework/container-utils";
|
|
11
|
-
import { IFluidHandle, IRequest } from "@fluidframework/core-interfaces";
|
|
11
|
+
import { IDisposable, IFluidHandle, IRequest } from "@fluidframework/core-interfaces";
|
|
12
12
|
import { FluidObjectHandle } from "@fluidframework/datastore";
|
|
13
13
|
import { ISequencedDocumentMessage, ISnapshotTree } from "@fluidframework/protocol-definitions";
|
|
14
14
|
import {
|
package/src/gc/gcDefinitions.ts
CHANGED
|
@@ -263,7 +263,6 @@ export interface IGarbageCollectorCreateParams {
|
|
|
263
263
|
readonly getLastSummaryTimestampMs: () => number | undefined;
|
|
264
264
|
readonly readAndParseBlob: ReadAndParseBlob;
|
|
265
265
|
readonly activeConnection: () => boolean;
|
|
266
|
-
readonly getContainerDiagnosticId: () => string;
|
|
267
266
|
}
|
|
268
267
|
|
|
269
268
|
export interface IGCRuntimeOptions {
|
package/src/index.ts
CHANGED
|
@@ -67,6 +67,8 @@ export {
|
|
|
67
67
|
OpActionEventListener,
|
|
68
68
|
OpActionEventName,
|
|
69
69
|
ICancellableSummarizerController,
|
|
70
|
+
SubmitSummaryFailureData,
|
|
71
|
+
SummaryStage,
|
|
70
72
|
} from "./summary";
|
|
71
73
|
export { IChunkedOp, unpackRuntimeMessage } from "./opLifecycle";
|
|
72
74
|
export { generateStableId, isStableId, assertIsStableId } from "./id-compressor";
|
|
@@ -29,6 +29,7 @@ const opOverhead = 200;
|
|
|
29
29
|
export class BatchManager {
|
|
30
30
|
private pendingBatch: BatchMessage[] = [];
|
|
31
31
|
private batchContentSize = 0;
|
|
32
|
+
private hasReentrantOps = false;
|
|
32
33
|
|
|
33
34
|
public get length() {
|
|
34
35
|
return this.pendingBatch.length;
|
|
@@ -54,9 +55,14 @@ export class BatchManager {
|
|
|
54
55
|
|
|
55
56
|
constructor(public readonly options: IBatchManagerOptions) {}
|
|
56
57
|
|
|
57
|
-
public push(
|
|
58
|
+
public push(
|
|
59
|
+
message: BatchMessage,
|
|
60
|
+
reentrant: boolean,
|
|
61
|
+
currentClientSequenceNumber?: number,
|
|
62
|
+
): boolean {
|
|
58
63
|
const contentSize = this.batchContentSize + (message.contents?.length ?? 0);
|
|
59
64
|
const opCount = this.pendingBatch.length;
|
|
65
|
+
this.hasReentrantOps = this.hasReentrantOps || reentrant;
|
|
60
66
|
|
|
61
67
|
// Attempt to estimate batch size, aka socket message size.
|
|
62
68
|
// Each op has pretty large envelope, estimating to be 200 bytes.
|
|
@@ -100,11 +106,13 @@ export class BatchManager {
|
|
|
100
106
|
content: this.pendingBatch,
|
|
101
107
|
contentSizeInBytes: this.batchContentSize,
|
|
102
108
|
referenceSequenceNumber: this.referenceSequenceNumber,
|
|
109
|
+
hasReentrantOps: this.hasReentrantOps,
|
|
103
110
|
};
|
|
104
111
|
|
|
105
112
|
this.pendingBatch = [];
|
|
106
113
|
this.batchContentSize = 0;
|
|
107
114
|
this.clientSequenceNumber = undefined;
|
|
115
|
+
this.hasReentrantOps = false;
|
|
108
116
|
|
|
109
117
|
return addBatchMetadata(batch);
|
|
110
118
|
}
|
|
@@ -34,6 +34,17 @@ export interface IBatch {
|
|
|
34
34
|
* The reference sequence number for the batch
|
|
35
35
|
*/
|
|
36
36
|
readonly referenceSequenceNumber: number | undefined;
|
|
37
|
+
/**
|
|
38
|
+
* Wether or not the batch contains at least one op which was produced as the result
|
|
39
|
+
* of processing another op. This means that the batch must be rebased before
|
|
40
|
+
* submitted, to ensure that all ops have the same reference sequence numbers and a
|
|
41
|
+
* consistent view of the data model. This happens when the op is created within a
|
|
42
|
+
* 'changed' event handler of a DDS and will have a different reference sequence number
|
|
43
|
+
* than the rest of the ops in the batch, meaning that it has a different view of the
|
|
44
|
+
* state of the data model, therefore all ops must be resubmitted and rebased to the current
|
|
45
|
+
* reference sequence number to be in agreement about the data model state.
|
|
46
|
+
*/
|
|
47
|
+
readonly hasReentrantOps?: boolean;
|
|
37
48
|
}
|
|
38
49
|
|
|
39
50
|
export interface IBatchCheckpoint {
|
package/src/opLifecycle/index.ts
CHANGED
|
@@ -11,7 +11,7 @@ export {
|
|
|
11
11
|
IChunkedOp,
|
|
12
12
|
IMessageProcessingResult,
|
|
13
13
|
} from "./definitions";
|
|
14
|
-
export { Outbox } from "./outbox";
|
|
14
|
+
export { Outbox, getLongStack } from "./outbox";
|
|
15
15
|
export { OpCompressor } from "./opCompressor";
|
|
16
16
|
export { OpDecompressor } from "./opDecompressor";
|
|
17
17
|
export { OpSplitter, splitOp } from "./opSplitter";
|
|
@@ -10,11 +10,11 @@ import {
|
|
|
10
10
|
MonitoringContext,
|
|
11
11
|
} from "@fluidframework/telemetry-utils";
|
|
12
12
|
import { assert } from "@fluidframework/common-utils";
|
|
13
|
-
import { IContainerContext } from "@fluidframework/container-definitions";
|
|
13
|
+
import { IContainerContext, ICriticalContainerError } from "@fluidframework/container-definitions";
|
|
14
14
|
import { GenericError, UsageError } from "@fluidframework/container-utils";
|
|
15
15
|
import { MessageType } from "@fluidframework/protocol-definitions";
|
|
16
16
|
import { ICompressionRuntimeOptions } from "../containerRuntime";
|
|
17
|
-
import { PendingStateManager } from "../pendingStateManager";
|
|
17
|
+
import { IPendingBatchMessage, PendingStateManager } from "../pendingStateManager";
|
|
18
18
|
import {
|
|
19
19
|
BatchManager,
|
|
20
20
|
BatchSequenceNumbers,
|
|
@@ -31,6 +31,7 @@ export interface IOutboxConfig {
|
|
|
31
31
|
// The maximum size of a batch that we can send over the wire.
|
|
32
32
|
readonly maxBatchSizeInBytes: number;
|
|
33
33
|
readonly disablePartialFlush: boolean;
|
|
34
|
+
readonly enableBatchRebasing: boolean;
|
|
34
35
|
}
|
|
35
36
|
|
|
36
37
|
export interface IOutboxParameters {
|
|
@@ -43,18 +44,40 @@ export interface IOutboxParameters {
|
|
|
43
44
|
readonly logger: ITelemetryLoggerExt;
|
|
44
45
|
readonly groupingManager: OpGroupingManager;
|
|
45
46
|
readonly getCurrentSequenceNumbers: () => BatchSequenceNumbers;
|
|
47
|
+
readonly reSubmit: (message: IPendingBatchMessage) => void;
|
|
48
|
+
readonly opReentrancy: () => boolean;
|
|
49
|
+
readonly closeContainer: (error?: ICriticalContainerError) => void;
|
|
46
50
|
}
|
|
47
51
|
|
|
48
|
-
|
|
49
|
-
|
|
52
|
+
/**
|
|
53
|
+
* Temporarily increase the stack limit while executing the provided action.
|
|
54
|
+
* If a negative value is provided for `length`, no stack frames will be collected.
|
|
55
|
+
* If Infinity is provided, all frames will be collected.
|
|
56
|
+
*
|
|
57
|
+
* ADO:4663 - add this to the common packages.
|
|
58
|
+
*
|
|
59
|
+
* @param action - action which returns an error
|
|
60
|
+
* @param length - number of stack frames to collect, 50 if unspecified.
|
|
61
|
+
* @returns the result of the action provided
|
|
62
|
+
*/
|
|
63
|
+
export function getLongStack<T>(action: () => T, length: number = 50): T {
|
|
64
|
+
const errorObj = Error as any;
|
|
65
|
+
if (
|
|
66
|
+
(
|
|
67
|
+
Object.getOwnPropertyDescriptor(errorObj, "stackTraceLimit") ||
|
|
68
|
+
Object.getOwnPropertyDescriptor(Object.getPrototypeOf(errorObj), "stackTraceLimit") ||
|
|
69
|
+
{}
|
|
70
|
+
).writable !== true
|
|
71
|
+
) {
|
|
72
|
+
return action();
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const originalStackTraceLimit = errorObj.stackTraceLimit;
|
|
50
76
|
try {
|
|
51
|
-
|
|
52
|
-
(Error as any).stackTraceLimit = 50;
|
|
53
|
-
const result = action();
|
|
54
|
-
(Error as any).stackTraceLimit = originalStackTraceLimit;
|
|
55
|
-
return result;
|
|
56
|
-
} catch (error) {
|
|
77
|
+
errorObj.stackTraceLimit = length;
|
|
57
78
|
return action();
|
|
79
|
+
} finally {
|
|
80
|
+
errorObj.stackTraceLimit = originalStackTraceLimit;
|
|
58
81
|
}
|
|
59
82
|
}
|
|
60
83
|
|
|
@@ -63,6 +86,8 @@ export class Outbox {
|
|
|
63
86
|
private readonly attachFlowBatch: BatchManager;
|
|
64
87
|
private readonly mainBatch: BatchManager;
|
|
65
88
|
private readonly defaultAttachFlowSoftLimitInBytes = 320 * 1024;
|
|
89
|
+
private batchRebasesToReport = 5;
|
|
90
|
+
private rebasing = false;
|
|
66
91
|
|
|
67
92
|
/**
|
|
68
93
|
* Track the number of ops which were detected to have a mismatched
|
|
@@ -132,7 +157,7 @@ export class Outbox {
|
|
|
132
157
|
}
|
|
133
158
|
|
|
134
159
|
if (!this.params.config.disablePartialFlush) {
|
|
135
|
-
this.
|
|
160
|
+
this.flushAll();
|
|
136
161
|
}
|
|
137
162
|
}
|
|
138
163
|
|
|
@@ -142,6 +167,7 @@ export class Outbox {
|
|
|
142
167
|
if (
|
|
143
168
|
!this.mainBatch.push(
|
|
144
169
|
message,
|
|
170
|
+
this.isContextReentrant(),
|
|
145
171
|
this.params.getCurrentSequenceNumbers().clientSequenceNumber,
|
|
146
172
|
)
|
|
147
173
|
) {
|
|
@@ -160,16 +186,18 @@ export class Outbox {
|
|
|
160
186
|
if (
|
|
161
187
|
!this.attachFlowBatch.push(
|
|
162
188
|
message,
|
|
189
|
+
this.isContextReentrant(),
|
|
163
190
|
this.params.getCurrentSequenceNumbers().clientSequenceNumber,
|
|
164
191
|
)
|
|
165
192
|
) {
|
|
166
193
|
// BatchManager has two limits - soft limit & hard limit. Soft limit is only engaged
|
|
167
194
|
// when queue is not empty.
|
|
168
195
|
// Flush queue & retry. Failure on retry would mean - single message is bigger than hard limit
|
|
169
|
-
this.flushInternal(this.attachFlowBatch
|
|
196
|
+
this.flushInternal(this.attachFlowBatch);
|
|
170
197
|
if (
|
|
171
198
|
!this.attachFlowBatch.push(
|
|
172
199
|
message,
|
|
200
|
+
this.isContextReentrant(),
|
|
173
201
|
this.params.getCurrentSequenceNumbers().clientSequenceNumber,
|
|
174
202
|
)
|
|
175
203
|
) {
|
|
@@ -191,22 +219,85 @@ export class Outbox {
|
|
|
191
219
|
this.attachFlowBatch.contentSizeInBytes >=
|
|
192
220
|
this.params.config.compressionOptions.minimumBatchSizeInBytes
|
|
193
221
|
) {
|
|
194
|
-
this.flushInternal(this.attachFlowBatch
|
|
222
|
+
this.flushInternal(this.attachFlowBatch);
|
|
195
223
|
}
|
|
196
224
|
}
|
|
197
225
|
|
|
198
226
|
public flush() {
|
|
199
|
-
|
|
200
|
-
|
|
227
|
+
if (this.isContextReentrant()) {
|
|
228
|
+
const error = new UsageError("Flushing is not supported inside DDS event handlers");
|
|
229
|
+
this.params.closeContainer(error);
|
|
230
|
+
throw error;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
this.flushAll();
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
private flushAll() {
|
|
237
|
+
this.flushInternal(this.attachFlowBatch);
|
|
238
|
+
this.flushInternal(this.mainBatch);
|
|
201
239
|
}
|
|
202
240
|
|
|
203
|
-
private flushInternal(
|
|
241
|
+
private flushInternal(batchManager: BatchManager) {
|
|
242
|
+
if (batchManager.empty) {
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
const rawBatch = batchManager.popBatch();
|
|
247
|
+
if (rawBatch.hasReentrantOps === true && this.params.config.enableBatchRebasing) {
|
|
248
|
+
assert(!this.rebasing, 0x6fa /* A rebased batch should never have reentrant ops */);
|
|
249
|
+
// If a batch contains reentrant ops (ops created as a result from processing another op)
|
|
250
|
+
// it needs to be rebased so that we can ensure consistent reference sequence numbers
|
|
251
|
+
// and eventual consistency at the DDS level.
|
|
252
|
+
this.rebase(rawBatch, batchManager);
|
|
253
|
+
return;
|
|
254
|
+
}
|
|
255
|
+
|
|
204
256
|
const processedBatch = this.compressBatch(rawBatch);
|
|
205
257
|
this.sendBatch(processedBatch);
|
|
206
258
|
|
|
207
259
|
this.persistBatch(rawBatch.content);
|
|
208
260
|
}
|
|
209
261
|
|
|
262
|
+
/**
|
|
263
|
+
* Rebases a batch. All the ops in the batch are resubmitted to the runtime and
|
|
264
|
+
* they will end up back in the same batch manager they were flushed from and subsequently flushed.
|
|
265
|
+
*
|
|
266
|
+
* @param rawBatch - the batch to be rebased
|
|
267
|
+
*/
|
|
268
|
+
private rebase(rawBatch: IBatch, batchManager: BatchManager) {
|
|
269
|
+
assert(!this.rebasing, 0x6fb /* Reentrancy */);
|
|
270
|
+
|
|
271
|
+
this.rebasing = true;
|
|
272
|
+
for (const message of rawBatch.content) {
|
|
273
|
+
this.params.reSubmit({
|
|
274
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
275
|
+
content: message.contents!,
|
|
276
|
+
localOpMetadata: message.localOpMetadata,
|
|
277
|
+
opMetadata: message.metadata,
|
|
278
|
+
});
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
if (this.batchRebasesToReport > 0) {
|
|
282
|
+
this.mc.logger.sendTelemetryEvent(
|
|
283
|
+
{
|
|
284
|
+
eventName: "BatchRebase",
|
|
285
|
+
length: rawBatch.content.length,
|
|
286
|
+
referenceSequenceNumber: rawBatch.referenceSequenceNumber,
|
|
287
|
+
},
|
|
288
|
+
new UsageError("BatchRebase"),
|
|
289
|
+
);
|
|
290
|
+
this.batchRebasesToReport--;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
this.flushInternal(batchManager);
|
|
294
|
+
this.rebasing = false;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
private isContextReentrant(): boolean {
|
|
298
|
+
return this.params.opReentrancy() && !this.rebasing;
|
|
299
|
+
}
|
|
300
|
+
|
|
210
301
|
private compressBatch(batch: IBatch): IBatch {
|
|
211
302
|
if (
|
|
212
303
|
batch.content.length === 0 ||
|
package/src/packageVersion.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* Licensed under the MIT License.
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import { IDisposable } from "@fluidframework/
|
|
6
|
+
import { IDisposable } from "@fluidframework/core-interfaces";
|
|
7
7
|
import { assert, Lazy } from "@fluidframework/common-utils";
|
|
8
8
|
import { ICriticalContainerError } from "@fluidframework/container-definitions";
|
|
9
9
|
import { DataProcessingError } from "@fluidframework/container-utils";
|
|
@@ -50,17 +50,19 @@ export interface IPendingLocalState {
|
|
|
50
50
|
pendingStates: IPendingState[];
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
+
export interface IPendingBatchMessage {
|
|
54
|
+
content: string;
|
|
55
|
+
localOpMetadata: unknown;
|
|
56
|
+
opMetadata: Record<string, unknown> | undefined;
|
|
57
|
+
}
|
|
58
|
+
|
|
53
59
|
export interface IRuntimeStateHandler {
|
|
54
60
|
connected(): boolean;
|
|
55
61
|
clientId(): string | undefined;
|
|
56
62
|
close(error?: ICriticalContainerError): void;
|
|
57
63
|
applyStashedOp(content: string): Promise<unknown>;
|
|
58
|
-
reSubmit(
|
|
59
|
-
|
|
60
|
-
localOpMetadata: unknown,
|
|
61
|
-
opMetadata: Record<string, unknown> | undefined,
|
|
62
|
-
): void;
|
|
63
|
-
orderSequentially(callback: () => void): void;
|
|
64
|
+
reSubmit(message: IPendingBatchMessage): void;
|
|
65
|
+
reSubmitBatch(batch: IPendingBatchMessage[]): void;
|
|
64
66
|
}
|
|
65
67
|
|
|
66
68
|
/**
|
|
@@ -379,35 +381,37 @@ export class PendingStateManager implements IDisposable {
|
|
|
379
381
|
0x554 /* Last pending message cannot be a batch begin */,
|
|
380
382
|
);
|
|
381
383
|
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
assert(pendingMessagesCount > 0, 0x555 /* No batch end found */);
|
|
395
|
-
|
|
396
|
-
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
397
|
-
pendingMessage = this.pendingMessages.shift()!;
|
|
398
|
-
pendingMessagesCount--;
|
|
399
|
-
assert(
|
|
400
|
-
pendingMessage.opMetadata?.batch !== true,
|
|
401
|
-
0x556 /* Batch start needs a corresponding batch end */,
|
|
402
|
-
);
|
|
384
|
+
const batch: IPendingBatchMessage[] = [];
|
|
385
|
+
|
|
386
|
+
// check is >= because batch end may be last pending message
|
|
387
|
+
while (pendingMessagesCount >= 0) {
|
|
388
|
+
batch.push({
|
|
389
|
+
content: pendingMessage.content,
|
|
390
|
+
localOpMetadata: pendingMessage.localOpMetadata,
|
|
391
|
+
opMetadata: pendingMessage.opMetadata,
|
|
392
|
+
});
|
|
393
|
+
|
|
394
|
+
if (pendingMessage.opMetadata?.batch === false) {
|
|
395
|
+
break;
|
|
403
396
|
}
|
|
404
|
-
|
|
397
|
+
assert(pendingMessagesCount > 0, 0x555 /* No batch end found */);
|
|
398
|
+
|
|
399
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
400
|
+
pendingMessage = this.pendingMessages.shift()!;
|
|
401
|
+
pendingMessagesCount--;
|
|
402
|
+
assert(
|
|
403
|
+
pendingMessage.opMetadata?.batch !== true,
|
|
404
|
+
0x556 /* Batch start needs a corresponding batch end */,
|
|
405
|
+
);
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
this.stateHandler.reSubmitBatch(batch);
|
|
405
409
|
} else {
|
|
406
|
-
this.stateHandler.reSubmit(
|
|
407
|
-
pendingMessage.content,
|
|
408
|
-
pendingMessage.localOpMetadata,
|
|
409
|
-
pendingMessage.opMetadata,
|
|
410
|
-
);
|
|
410
|
+
this.stateHandler.reSubmit({
|
|
411
|
+
content: pendingMessage.content,
|
|
412
|
+
localOpMetadata: pendingMessage.localOpMetadata,
|
|
413
|
+
opMetadata: pendingMessage.opMetadata,
|
|
414
|
+
});
|
|
411
415
|
}
|
|
412
416
|
}
|
|
413
417
|
}
|