@fluidframework/container-runtime 0.51.0 → 0.52.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/dist/connectionTelemetry.d.ts +4 -0
- package/dist/connectionTelemetry.d.ts.map +1 -1
- package/dist/connectionTelemetry.js +6 -2
- package/dist/connectionTelemetry.js.map +1 -1
- package/dist/containerRuntime.d.ts +23 -11
- package/dist/containerRuntime.d.ts.map +1 -1
- package/dist/containerRuntime.js +173 -93
- package/dist/containerRuntime.js.map +1 -1
- package/dist/dataStoreContext.d.ts +7 -7
- package/dist/dataStoreContext.d.ts.map +1 -1
- package/dist/dataStoreContext.js +1 -1
- package/dist/dataStoreContext.js.map +1 -1
- package/dist/dataStores.js +2 -1
- package/dist/dataStores.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/summarizerTypes.d.ts +13 -2
- package/dist/summarizerTypes.d.ts.map +1 -1
- package/dist/summarizerTypes.js +3 -0
- package/dist/summarizerTypes.js.map +1 -1
- package/dist/summaryFormat.js +2 -1
- package/dist/summaryFormat.js.map +1 -1
- package/dist/summaryManager.d.ts.map +1 -1
- package/dist/summaryManager.js.map +1 -1
- package/lib/connectionTelemetry.d.ts +4 -0
- package/lib/connectionTelemetry.d.ts.map +1 -1
- package/lib/connectionTelemetry.js +5 -1
- package/lib/connectionTelemetry.js.map +1 -1
- package/lib/containerRuntime.d.ts +23 -11
- package/lib/containerRuntime.d.ts.map +1 -1
- package/lib/containerRuntime.js +177 -97
- package/lib/containerRuntime.js.map +1 -1
- package/lib/dataStoreContext.d.ts +7 -7
- package/lib/dataStoreContext.d.ts.map +1 -1
- package/lib/dataStoreContext.js +1 -1
- package/lib/dataStoreContext.js.map +1 -1
- package/lib/dataStores.js +2 -1
- package/lib/dataStores.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/summarizerTypes.d.ts +13 -2
- package/lib/summarizerTypes.d.ts.map +1 -1
- package/lib/summarizerTypes.js +3 -0
- package/lib/summarizerTypes.js.map +1 -1
- package/lib/summaryFormat.js +2 -1
- package/lib/summaryFormat.js.map +1 -1
- package/lib/summaryManager.d.ts.map +1 -1
- package/lib/summaryManager.js.map +1 -1
- package/package.json +16 -16
- package/src/connectionTelemetry.ts +6 -1
- package/src/containerRuntime.ts +220 -110
- package/src/dataStoreContext.ts +7 -7
- package/src/packageVersion.ts +1 -1
- package/src/summarizerTypes.ts +16 -3
- package/src/summaryManager.ts +8 -3
|
@@ -5,5 +5,9 @@
|
|
|
5
5
|
import { ITelemetryLogger } from "@fluidframework/common-definitions";
|
|
6
6
|
import { IDeltaManager } from "@fluidframework/container-definitions";
|
|
7
7
|
import { IDocumentMessage, ISequencedDocumentMessage } from "@fluidframework/protocol-definitions";
|
|
8
|
+
/**
|
|
9
|
+
* We report various latency-related errors when waiting for op roundtrip takes longer than that amout of time.
|
|
10
|
+
*/
|
|
11
|
+
export declare const latencyThreshold = 5000;
|
|
8
12
|
export declare function ReportOpPerfTelemetry(clientId: string | undefined, deltaManager: IDeltaManager<ISequencedDocumentMessage, IDocumentMessage>, logger: ITelemetryLogger): void;
|
|
9
13
|
//# sourceMappingURL=connectionTelemetry.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"connectionTelemetry.d.ts","sourceRoot":"","sources":["../src/connectionTelemetry.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,oCAAoC,CAAC;AAEtE,OAAO,EAAE,aAAa,EAAE,MAAM,uCAAuC,CAAC;AACtE,OAAO,EACH,gBAAgB,EAChB,yBAAyB,EAC5B,MAAM,sCAAsC,CAAC;
|
|
1
|
+
{"version":3,"file":"connectionTelemetry.d.ts","sourceRoot":"","sources":["../src/connectionTelemetry.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,oCAAoC,CAAC;AAEtE,OAAO,EAAE,aAAa,EAAE,MAAM,uCAAuC,CAAC;AACtE,OAAO,EACH,gBAAgB,EAChB,yBAAyB,EAC5B,MAAM,sCAAsC,CAAC;AAG9C;;GAEG;AACH,eAAO,MAAM,gBAAgB,OAAO,CAAC;AAwJrC,wBAAgB,qBAAqB,CACjC,QAAQ,EAAE,MAAM,GAAG,SAAS,EAC5B,YAAY,EAAE,aAAa,CAAC,yBAAyB,EAAE,gBAAgB,CAAC,EACxE,MAAM,EAAE,gBAAgB,QAE3B"}
|
|
@@ -4,9 +4,13 @@
|
|
|
4
4
|
* Licensed under the MIT License.
|
|
5
5
|
*/
|
|
6
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
-
exports.ReportOpPerfTelemetry = void 0;
|
|
7
|
+
exports.ReportOpPerfTelemetry = exports.latencyThreshold = void 0;
|
|
8
8
|
const telemetry_utils_1 = require("@fluidframework/telemetry-utils");
|
|
9
9
|
const common_utils_1 = require("@fluidframework/common-utils");
|
|
10
|
+
/**
|
|
11
|
+
* We report various latency-related errors when waiting for op roundtrip takes longer than that amout of time.
|
|
12
|
+
*/
|
|
13
|
+
exports.latencyThreshold = 5000;
|
|
10
14
|
class OpPerfTelemetry {
|
|
11
15
|
constructor(clientId, deltaManager, logger) {
|
|
12
16
|
this.clientId = clientId;
|
|
@@ -115,7 +119,7 @@ class OpPerfTelemetry {
|
|
|
115
119
|
// that results in overwhelming ordering service and thus starting to see long latencies.
|
|
116
120
|
// The threshold could be adjusted, but ideally it stays workload-agnostic, as service
|
|
117
121
|
// performance impacts all workloads relying on service.
|
|
118
|
-
const category = duration >
|
|
122
|
+
const category = duration > exports.latencyThreshold ? "error" : "performance";
|
|
119
123
|
this.logger.sendPerformanceEvent({
|
|
120
124
|
eventName: "OpRoundtripTime",
|
|
121
125
|
sequenceNumber,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"connectionTelemetry.js","sourceRoot":"","sources":["../src/connectionTelemetry.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAGH,qEAA+E;AAM/E,+DAAmE;AAEnE,MAAM,eAAe;IAmBjB,YACY,QAA4B,EACnB,YAAwE,EACzF,MAAwB;QAFhB,aAAQ,GAAR,QAAQ,CAAoB;QACnB,iBAAY,GAAZ,YAAY,CAA4D;QApBrF,cAAS,GAAW,CAAC,CAAC;QACtB,kBAAa,GAAG,CAAC,CAAC;QASlB,oBAAe,GAAG,IAAI,CAAC;QAEd,aAAQ,GAAG,0BAAW,CAAC,GAAG,EAAE,CAAC;QACtC,wBAAmB,GAAG,CAAC,CAAC;QACxB,QAAG,GAAG,CAAC,CAAC;QAQZ,IAAI,CAAC,MAAM,GAAG,6BAAW,CAAC,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;QAEnD,IAAI,CAAC,YAAY,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC,CAAC;QACxE,IAAI,CAAC,YAAY,CAAC,EAAE,CAAC,UAAU,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC,CAAC;QAE5E,IAAI,CAAC,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,IAAI,CAAC,iBAAiB,CAAC,OAAO,CAAC,CAAC,CAAC;QAEzE,IAAI,CAAC,YAAY,CAAC,EAAE,CAAC,SAAS,EAAE,CAAC,OAAO,EAAE,SAAS,EAAE,EAAE;YACnD,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC;YACjC,IAAI,SAAS,KAAK,SAAS,EAAE;gBACzB,IAAI,CAAC,qBAAqB,GAAG,IAAI,CAAC,YAAY,CAAC,kBAAkB,CAAC;gBAClE,IAAI,CAAC,GAAG,GAAG,SAAS,CAAC;gBACrB,IAAI,CAAC,mBAAmB,GAAG,0BAAW,CAAC,GAAG,EAAE,CAAC;gBAE7C,6DAA6D;gBAC7D,IAAI,IAAI,CAAC,GAAG,IAAI,CAAC,EAAE;oBACf,IAAI,CAAC,qBAAqB,EAAE,CAAC;iBAChC;aACJ;QACL,CAAC,CAAC,CAAC;QACH,IAAI,CAAC,YAAY,CAAC,EAAE,CAAC,YAAY,EAAE,GAAG,EAAE;YACpC,IAAI,CAAC,wCAAwC,GAAG,SAAS,CAAC;YAC1D,IAAI,CAAC,qBAAqB,GAAG,SAAS,CAAC;YACvC,IAAI,CAAC,eAAe,GAAG,KAAK,CAAC;QACjC,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAa,EAAE,QAAgB,EAAE,EAAE;YACrE,oCAAoC;YACpC,gGAAgG;YAChG,0GAA0G;YAC1G,uBAAuB;YACvB,4FAA4F;YAC5F,8BAA8B;YAC9B,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,IAAI,GAAG,EAAE;gBAC3C,IAAI,CAAC,MAAM,CAAC,oBAAoB,CAAC;oBAC7B,SAAS,EAAE,wBAAwB;oBACnC,KAAK;oBACL,QAAQ;iBACX,CAAC,CAAC;aACN;QACL,CAAC,CAAC,CAAC;IACP,CAAC;IAEO,qBAAqB;QACzB,IAAI,CAAC,qBAAqB,GAAG,SAAS,CAAC;QACvC,IAAI,CAAC,MAAM,CAAC,oBAAoB,CAAC;YAC7B,SAAS,EAAE,iBAAiB;YAC5B,QAAQ,EAAE,0BAAW,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,mBAAmB;YACtD,GAAG,EAAE,IAAI,CAAC,GAAG;YACb,mDAAmD;YACnD,aAAa,EAAE,IAAI,CAAC,eAAe,CAAC,CAAC;gBACjC,iCAAe,CAAC,UAAU,CAAC,IAAI,CAAC,mBAAmB,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC;gBACtE,SAAS;YACb,eAAe,EAAE,IAAI,CAAC,eAAe;SACxC,CAAC,CAAC;IACP,CAAC;IAEO,cAAc,CAAC,OAAe;QAClC,IAAI,CAAC,SAAS,EAAE,CAAC;QACjB,IAAI,CAAC,aAAa,IAAI,OAAO,CAAC;QAC9B,MAAM,cAAc,GAAG,GAAG,CAAC;QAC3B,IAAI,IAAI,CAAC,SAAS,KAAK,cAAc,EAAE;YACnC,IAAI,CAAC,MAAM,CAAC,oBAAoB,CAAC;gBAC7B,SAAS,EAAE,cAAc;gBACzB,QAAQ,EAAE,IAAI,CAAC,aAAa,GAAG,cAAc;aAChD,CAAC,CAAC;YACH,IAAI,CAAC,SAAS,GAAG,CAAC,CAAC;YACnB,IAAI,CAAC,aAAa,GAAG,CAAC,CAAC;SAC1B;IACL,CAAC;IAEO,cAAc,CAAC,OAAyB;QAC5C,sEAAsE;QACtE,IAAI,IAAI,CAAC,wCAAwC,KAAK,SAAS,IAAI,OAAO,CAAC,oBAAoB,GAAG,GAAG,KAAK,CAAC,EAAE;YACzG,IAAI,CAAC,8BAA8B,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;YACjD,IAAI,CAAC,wCAAwC,GAAG,OAAO,CAAC,oBAAoB,CAAC;SAChF;IACL,CAAC;IAEO,iBAAiB,CAAC,OAAkC;QACxD,MAAM,cAAc,GAAG,OAAO,CAAC,cAAc,CAAC;QAE9C,IAAI,cAAc,KAAK,IAAI,CAAC,qBAAqB,EAAE;YAC/C,IAAI,CAAC,qBAAqB,EAAE,CAAC;SAChC;QAED,uDAAuD;QACvD,IAAI,cAAc,GAAG,IAAI,KAAK,CAAC,EAAE;YAC7B,IAAI,IAAI,CAAC,8CAA8C,KAAK,SAAS,EAAE;gBACnE,IAAI,CAAC,MAAM,CAAC,oBAAoB,CAAC;oBAC7B,SAAS,EAAE,eAAe;oBAC1B,cAAc;oBACd,WAAW,EAAE,IAAI,CAAC,YAAY,CAAC,kBAAkB,GAAG,IAAI,CAAC,YAAY,CAAC,qBAAqB;oBAC3F,QAAQ,EAAE,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC,8CAA8C;iBACpF,CAAC,CAAC;aACN;YACD,IAAI,CAAC,8CAA8C,GAAG,OAAO,CAAC,SAAS,CAAC;SAC3E;QAED,IAAI,IAAI,CAAC,QAAQ,KAAK,OAAO,CAAC,QAAQ;YAClC,IAAI,CAAC,wCAAwC,KAAK,OAAO,CAAC,oBAAoB,EAAE;YAChF,qBAAM,CAAC,IAAI,CAAC,8BAA8B,KAAK,SAAS,EACpD,KAAK,CAAC,mDAAmD,CAAC,CAAC;YAE/D,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,8BAA8B,CAAC;YAElE,gEAAgE;YAChE,mFAAmF;YACnF,mBAAmB;YACnB,0FAA0F;YAC1F,yFAAyF;YACzF,uFAAuF;YACvF,wDAAwD;YACxD,MAAM,QAAQ,GAAG,QAAQ,GAAG,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,aAAa,CAAC;YAE3D,IAAI,CAAC,MAAM,CAAC,oBAAoB,CAAC;gBAC7B,SAAS,EAAE,iBAAiB;gBAC5B,cAAc;gBACd,uBAAuB,EAAE,OAAO,CAAC,uBAAuB;gBACxD,QAAQ;gBACR,QAAQ;aACX,CAAC,CAAC;YACH,IAAI,CAAC,wCAAwC,GAAG,SAAS,CAAC;SAC7D;IACL,CAAC;CACJ;AAED,SAAgB,qBAAqB,CACjC,QAA4B,EAC5B,YAAwE,EACxE,MAAwB;IACxB,IAAI,eAAe,CAAC,QAAQ,EAAE,YAAY,EAAE,MAAM,CAAC,CAAC;AACxD,CAAC;AALD,sDAKC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { ITelemetryLogger } from \"@fluidframework/common-definitions\";\nimport { ChildLogger, TelemetryLogger } from \"@fluidframework/telemetry-utils\";\nimport { IDeltaManager } from \"@fluidframework/container-definitions\";\nimport {\n IDocumentMessage,\n ISequencedDocumentMessage,\n} from \"@fluidframework/protocol-definitions\";\nimport { assert, performance } from \"@fluidframework/common-utils\";\n\nclass OpPerfTelemetry {\n private pongCount: number = 0;\n private socketLatency = 0;\n\n // Collab window tracking. This is timestamp of %1000 message.\n private opSendTimeForLatencyStatisticsForMsnStatistics: number | undefined;\n\n // To track round trip time for every %1000 client message.\n private opSendTimeForLatencyStatistics: number | undefined;\n private clientSequenceNumberForLatencyStatistics: number | undefined;\n\n private firstConnection = true;\n private connectionOpSeqNumber: number | undefined;\n private readonly bootTime = performance.now();\n private connectionStartTime = 0;\n private gap = 0;\n\n private readonly logger: ITelemetryLogger;\n\n public constructor(\n private clientId: string | undefined,\n private readonly deltaManager: IDeltaManager<ISequencedDocumentMessage, IDocumentMessage>,\n logger: ITelemetryLogger) {\n this.logger = ChildLogger.create(logger, \"OpPerf\");\n\n this.deltaManager.on(\"pong\", (latency) => this.recordPingTime(latency));\n this.deltaManager.on(\"submitOp\", (message) => this.beforeOpSubmit(message));\n\n this.deltaManager.on(\"op\", (message) => this.afterProcessingOp(message));\n\n this.deltaManager.on(\"connect\", (details, opsBehind) => {\n this.clientId = details.clientId;\n if (opsBehind !== undefined) {\n this.connectionOpSeqNumber = this.deltaManager.lastKnownSeqNumber;\n this.gap = opsBehind;\n this.connectionStartTime = performance.now();\n\n // We might be already up-today. If so, report it right away.\n if (this.gap <= 0) {\n this.reportGettingUpToDate();\n }\n }\n });\n this.deltaManager.on(\"disconnect\", () => {\n this.clientSequenceNumberForLatencyStatistics = undefined;\n this.connectionOpSeqNumber = undefined;\n this.firstConnection = false;\n });\n\n this.deltaManager.inbound.on(\"idle\", (count: number, duration: number) => {\n // Do not want to log zero for sure.\n // We are more interested in aggregates, so logging only if we are processing some number of ops\n // Cut-off is arbitrary - can be increased or decreased based on amount of data collected and questions we\n // want to get answered\n // back-compat: Once 0.36 loader version saturates (count & duration args were added there),\n // we can remove typeof check.\n if (typeof count === \"number\" && count >= 100) {\n this.logger.sendPerformanceEvent({\n eventName: \"GetDeltas_OpProcessing\",\n count,\n duration,\n });\n }\n });\n }\n\n private reportGettingUpToDate() {\n this.connectionOpSeqNumber = undefined;\n this.logger.sendPerformanceEvent({\n eventName: \"ConnectionSpeed\",\n duration: performance.now() - this.connectionStartTime,\n ops: this.gap,\n // track time to connect only for first connection.\n timeToConnect: this.firstConnection ?\n TelemetryLogger.formatTick(this.connectionStartTime - this.bootTime) :\n undefined,\n firstConnection: this.firstConnection,\n });\n }\n\n private recordPingTime(latency: number) {\n this.pongCount++;\n this.socketLatency += latency;\n const aggregateCount = 100;\n if (this.pongCount === aggregateCount) {\n this.logger.sendPerformanceEvent({\n eventName: \"DeltaLatency\",\n duration: this.socketLatency / aggregateCount,\n });\n this.pongCount = 0;\n this.socketLatency = 0;\n }\n }\n\n private beforeOpSubmit(message: IDocumentMessage) {\n // start with first client op and measure latency every 500 client ops\n if (this.clientSequenceNumberForLatencyStatistics === undefined && message.clientSequenceNumber % 500 === 1) {\n this.opSendTimeForLatencyStatistics = Date.now();\n this.clientSequenceNumberForLatencyStatistics = message.clientSequenceNumber;\n }\n }\n\n private afterProcessingOp(message: ISequencedDocumentMessage) {\n const sequenceNumber = message.sequenceNumber;\n\n if (sequenceNumber === this.connectionOpSeqNumber) {\n this.reportGettingUpToDate();\n }\n\n // Record collab window max size after every 1000th op.\n if (sequenceNumber % 1000 === 0) {\n if (this.opSendTimeForLatencyStatisticsForMsnStatistics !== undefined) {\n this.logger.sendPerformanceEvent({\n eventName: \"MsnStatistics\",\n sequenceNumber,\n msnDistance: this.deltaManager.lastSequenceNumber - this.deltaManager.minimumSequenceNumber,\n duration: message.timestamp - this.opSendTimeForLatencyStatisticsForMsnStatistics,\n });\n }\n this.opSendTimeForLatencyStatisticsForMsnStatistics = message.timestamp;\n }\n\n if (this.clientId === message.clientId &&\n this.clientSequenceNumberForLatencyStatistics === message.clientSequenceNumber) {\n assert(this.opSendTimeForLatencyStatistics !== undefined,\n 0x120 /* \"Undefined latency statistics (op send time)\" */);\n\n const duration = Date.now() - this.opSendTimeForLatencyStatistics;\n\n // One of the core expectations for Fluid service is to be fast.\n // When it's not the case, we want to learn about it and be able to investigate, so\n // raise awareness.\n // This also helps identify cases where it's due to client behavior (sending too many ops)\n // that results in overwhelming ordering service and thus starting to see long latencies.\n // The threshold could be adjusted, but ideally it stays workload-agnostic, as service\n // performance impacts all workloads relying on service.\n const category = duration > 5000 ? \"error\" : \"performance\";\n\n this.logger.sendPerformanceEvent({\n eventName: \"OpRoundtripTime\",\n sequenceNumber,\n referenceSequenceNumber: message.referenceSequenceNumber,\n duration,\n category,\n });\n this.clientSequenceNumberForLatencyStatistics = undefined;\n }\n }\n}\n\nexport function ReportOpPerfTelemetry(\n clientId: string | undefined,\n deltaManager: IDeltaManager<ISequencedDocumentMessage, IDocumentMessage>,\n logger: ITelemetryLogger) {\n new OpPerfTelemetry(clientId, deltaManager, logger);\n}\n"]}
|
|
1
|
+
{"version":3,"file":"connectionTelemetry.js","sourceRoot":"","sources":["../src/connectionTelemetry.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { ITelemetryLogger } from \"@fluidframework/common-definitions\";\nimport { ChildLogger, TelemetryLogger } from \"@fluidframework/telemetry-utils\";\nimport { IDeltaManager } from \"@fluidframework/container-definitions\";\nimport {\n IDocumentMessage,\n ISequencedDocumentMessage,\n} from \"@fluidframework/protocol-definitions\";\nimport { assert, performance } from \"@fluidframework/common-utils\";\n\n/**\n * We report various latency-related errors when waiting for op roundtrip takes longer than that amout of time.\n */\nexport const latencyThreshold = 5000;\n\nclass OpPerfTelemetry {\n private pongCount: number = 0;\n private socketLatency = 0;\n\n // Collab window tracking. This is timestamp of %1000 message.\n private opSendTimeForLatencyStatisticsForMsnStatistics: number | undefined;\n\n // To track round trip time for every %1000 client message.\n private opSendTimeForLatencyStatistics: number | undefined;\n private clientSequenceNumberForLatencyStatistics: number | undefined;\n\n private firstConnection = true;\n private connectionOpSeqNumber: number | undefined;\n private readonly bootTime = performance.now();\n private connectionStartTime = 0;\n private gap = 0;\n\n private readonly logger: ITelemetryLogger;\n\n public constructor(\n private clientId: string | undefined,\n private readonly deltaManager: IDeltaManager<ISequencedDocumentMessage, IDocumentMessage>,\n logger: ITelemetryLogger) {\n this.logger = ChildLogger.create(logger, \"OpPerf\");\n\n this.deltaManager.on(\"pong\", (latency) => this.recordPingTime(latency));\n this.deltaManager.on(\"submitOp\", (message) => this.beforeOpSubmit(message));\n\n this.deltaManager.on(\"op\", (message) => this.afterProcessingOp(message));\n\n this.deltaManager.on(\"connect\", (details, opsBehind) => {\n this.clientId = details.clientId;\n if (opsBehind !== undefined) {\n this.connectionOpSeqNumber = this.deltaManager.lastKnownSeqNumber;\n this.gap = opsBehind;\n this.connectionStartTime = performance.now();\n\n // We might be already up-today. If so, report it right away.\n if (this.gap <= 0) {\n this.reportGettingUpToDate();\n }\n }\n });\n this.deltaManager.on(\"disconnect\", () => {\n this.clientSequenceNumberForLatencyStatistics = undefined;\n this.connectionOpSeqNumber = undefined;\n this.firstConnection = false;\n });\n\n this.deltaManager.inbound.on(\"idle\", (count: number, duration: number) => {\n // Do not want to log zero for sure.\n // We are more interested in aggregates, so logging only if we are processing some number of ops\n // Cut-off is arbitrary - can be increased or decreased based on amount of data collected and questions we\n // want to get answered\n // back-compat: Once 0.36 loader version saturates (count & duration args were added there),\n // we can remove typeof check.\n if (typeof count === \"number\" && count >= 100) {\n this.logger.sendPerformanceEvent({\n eventName: \"GetDeltas_OpProcessing\",\n count,\n duration,\n });\n }\n });\n }\n\n private reportGettingUpToDate() {\n this.connectionOpSeqNumber = undefined;\n this.logger.sendPerformanceEvent({\n eventName: \"ConnectionSpeed\",\n duration: performance.now() - this.connectionStartTime,\n ops: this.gap,\n // track time to connect only for first connection.\n timeToConnect: this.firstConnection ?\n TelemetryLogger.formatTick(this.connectionStartTime - this.bootTime) :\n undefined,\n firstConnection: this.firstConnection,\n });\n }\n\n private recordPingTime(latency: number) {\n this.pongCount++;\n this.socketLatency += latency;\n const aggregateCount = 100;\n if (this.pongCount === aggregateCount) {\n this.logger.sendPerformanceEvent({\n eventName: \"DeltaLatency\",\n duration: this.socketLatency / aggregateCount,\n });\n this.pongCount = 0;\n this.socketLatency = 0;\n }\n }\n\n private beforeOpSubmit(message: IDocumentMessage) {\n // start with first client op and measure latency every 500 client ops\n if (this.clientSequenceNumberForLatencyStatistics === undefined && message.clientSequenceNumber % 500 === 1) {\n this.opSendTimeForLatencyStatistics = Date.now();\n this.clientSequenceNumberForLatencyStatistics = message.clientSequenceNumber;\n }\n }\n\n private afterProcessingOp(message: ISequencedDocumentMessage) {\n const sequenceNumber = message.sequenceNumber;\n\n if (sequenceNumber === this.connectionOpSeqNumber) {\n this.reportGettingUpToDate();\n }\n\n // Record collab window max size after every 1000th op.\n if (sequenceNumber % 1000 === 0) {\n if (this.opSendTimeForLatencyStatisticsForMsnStatistics !== undefined) {\n this.logger.sendPerformanceEvent({\n eventName: \"MsnStatistics\",\n sequenceNumber,\n msnDistance: this.deltaManager.lastSequenceNumber - this.deltaManager.minimumSequenceNumber,\n duration: message.timestamp - this.opSendTimeForLatencyStatisticsForMsnStatistics,\n });\n }\n this.opSendTimeForLatencyStatisticsForMsnStatistics = message.timestamp;\n }\n\n if (this.clientId === message.clientId &&\n this.clientSequenceNumberForLatencyStatistics === message.clientSequenceNumber) {\n assert(this.opSendTimeForLatencyStatistics !== undefined,\n 0x120 /* \"Undefined latency statistics (op send time)\" */);\n\n const duration = Date.now() - this.opSendTimeForLatencyStatistics;\n\n // One of the core expectations for Fluid service is to be fast.\n // When it's not the case, we want to learn about it and be able to investigate, so\n // raise awareness.\n // This also helps identify cases where it's due to client behavior (sending too many ops)\n // that results in overwhelming ordering service and thus starting to see long latencies.\n // The threshold could be adjusted, but ideally it stays workload-agnostic, as service\n // performance impacts all workloads relying on service.\n const category = duration > latencyThreshold ? \"error\" : \"performance\";\n\n this.logger.sendPerformanceEvent({\n eventName: \"OpRoundtripTime\",\n sequenceNumber,\n referenceSequenceNumber: message.referenceSequenceNumber,\n duration,\n category,\n });\n this.clientSequenceNumberForLatencyStatistics = undefined;\n }\n }\n}\n\nexport function ReportOpPerfTelemetry(\n clientId: string | undefined,\n deltaManager: IDeltaManager<ISequencedDocumentMessage, IDocumentMessage>,\n logger: ITelemetryLogger) {\n new OpPerfTelemetry(clientId, deltaManager, logger);\n}\n"]}
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
/// <reference types="node" />
|
|
6
6
|
import { EventEmitter } from "events";
|
|
7
7
|
import { ITelemetryLogger } from "@fluidframework/common-definitions";
|
|
8
|
-
import { IFluidObject, IFluidRouter, IFluidHandleContext, IFluidSerializer, IRequest, IResponse, IFluidHandle, IFluidConfiguration } from "@fluidframework/core-interfaces";
|
|
8
|
+
import { IFluidObject, IFluidRouter, IFluidHandleContext, IFluidSerializer, IRequest, IResponse, IFluidHandle, IFluidConfiguration, FluidObject } from "@fluidframework/core-interfaces";
|
|
9
9
|
import { IAudience, IFluidTokenProvider, IContainerContext, IDeltaManager, IRuntime, ContainerWarning, ICriticalContainerError, AttachState, ILoaderOptions } from "@fluidframework/container-definitions";
|
|
10
10
|
import { IContainerRuntime, IContainerRuntimeEvents } from "@fluidframework/container-runtime-definitions";
|
|
11
11
|
import { TypedEventEmitter } from "@fluidframework/common-utils";
|
|
@@ -59,6 +59,11 @@ export interface IGCRuntimeOptions {
|
|
|
59
59
|
}
|
|
60
60
|
export interface ISummaryRuntimeOptions {
|
|
61
61
|
/**
|
|
62
|
+
* Flag that disables summaries if it is set to true.
|
|
63
|
+
*/
|
|
64
|
+
disableSummaries?: boolean;
|
|
65
|
+
/**
|
|
66
|
+
* @deprecated - To disable summaries, please set disableSummaries===true.
|
|
62
67
|
* Flag that will generate summaries if connected to a service that supports them.
|
|
63
68
|
* This defaults to true and must be explicitly set to false to disable.
|
|
64
69
|
*/
|
|
@@ -94,21 +99,24 @@ export interface IContainerRuntimeOptions {
|
|
|
94
99
|
}
|
|
95
100
|
export declare function isRuntimeMessage(message: ISequencedDocumentMessage): boolean;
|
|
96
101
|
export declare function unpackRuntimeMessage(message: ISequencedDocumentMessage): ISequencedDocumentMessage;
|
|
102
|
+
/**
|
|
103
|
+
* This class has the following responsibilities:
|
|
104
|
+
* 1. It tracks batches as we process ops and raises "batchBegin" and "batchEnd" events.
|
|
105
|
+
* As part of it, it validates batch correctness (i.e. no system ops in the middle of batch)
|
|
106
|
+
* 2. It creates instance of ScheduleManagerCore that ensures we never start processing ops from batch
|
|
107
|
+
* unless all ops of the batch are in.
|
|
108
|
+
*/
|
|
97
109
|
export declare class ScheduleManager {
|
|
98
110
|
private readonly deltaManager;
|
|
99
111
|
private readonly emitter;
|
|
100
112
|
private readonly logger;
|
|
101
113
|
private readonly deltaScheduler;
|
|
102
|
-
private pauseSequenceNumber;
|
|
103
|
-
private pauseClientId;
|
|
104
|
-
private localPaused;
|
|
105
114
|
private batchClientId;
|
|
115
|
+
private hitError;
|
|
116
|
+
private readonly scheduler;
|
|
106
117
|
constructor(deltaManager: IDeltaManager<ISequencedDocumentMessage, IDocumentMessage>, emitter: EventEmitter, logger: ITelemetryLogger);
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
setPaused(localPaused: boolean): void;
|
|
110
|
-
private updatePauseState;
|
|
111
|
-
private trackPending;
|
|
118
|
+
beforeOpProcessing(message: ISequencedDocumentMessage): void;
|
|
119
|
+
afterOpProcessing(error: any | undefined, message: ISequencedDocumentMessage): void;
|
|
112
120
|
}
|
|
113
121
|
/**
|
|
114
122
|
* Legacy ID for the built-in AgentScheduler. To minimize disruption while removing it, retaining this as a
|
|
@@ -143,7 +151,7 @@ export declare class ContainerRuntime extends TypedEventEmitter<IContainerRuntim
|
|
|
143
151
|
* @param runtimeOptions - Additional options to be passed to the runtime
|
|
144
152
|
* @param existing - (optional) When loading from an existing snapshot. Precedes context.existing if provided
|
|
145
153
|
*/
|
|
146
|
-
static load(context: IContainerContext, registryEntries: NamedFluidDataStoreRegistryEntries, requestHandler?: (request: IRequest, runtime: IContainerRuntime) => Promise<IResponse>, runtimeOptions?: IContainerRuntimeOptions, containerScope?:
|
|
154
|
+
static load(context: IContainerContext, registryEntries: NamedFluidDataStoreRegistryEntries, requestHandler?: (request: IRequest, runtime: IContainerRuntime) => Promise<IResponse>, runtimeOptions?: IContainerRuntimeOptions, containerScope?: FluidObject, existing?: boolean): Promise<ContainerRuntime>;
|
|
147
155
|
get id(): string;
|
|
148
156
|
get options(): ILoaderOptions;
|
|
149
157
|
get clientId(): string | undefined;
|
|
@@ -153,7 +161,7 @@ export declare class ContainerRuntime extends TypedEventEmitter<IContainerRuntim
|
|
|
153
161
|
get reSubmitFn(): (type: ContainerMessageType, content: any, localOpMetadata: unknown, opMetadata: Record<string, unknown> | undefined) => void;
|
|
154
162
|
get closeFn(): (error?: ICriticalContainerError) => void;
|
|
155
163
|
get flushMode(): FlushMode;
|
|
156
|
-
get scope(): IFluidObject;
|
|
164
|
+
get scope(): IFluidObject & FluidObject;
|
|
157
165
|
get IFluidDataStoreRegistry(): IFluidDataStoreRegistry;
|
|
158
166
|
get attachState(): AttachState;
|
|
159
167
|
readonly IFluidSerializer: IFluidSerializer;
|
|
@@ -373,6 +381,10 @@ export declare class ContainerRuntime extends TypedEventEmitter<IContainerRuntim
|
|
|
373
381
|
private refreshLatestSummaryAckFromServer;
|
|
374
382
|
private fetchSnapshotFromStorage;
|
|
375
383
|
getPendingLocalState(): IPendingLocalState | undefined;
|
|
384
|
+
/**
|
|
385
|
+
* @returns true if summaries are explicitly disabled for this ContainerRuntime, false otherwise
|
|
386
|
+
*/
|
|
387
|
+
summariesDisabled(): boolean;
|
|
376
388
|
readonly summarizeOnDemand: ISummarizer["summarizeOnDemand"];
|
|
377
389
|
readonly enqueueSummarize: ISummarizer["enqueueSummarize"];
|
|
378
390
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"containerRuntime.d.ts","sourceRoot":"","sources":["../src/containerRuntime.ts"],"names":[],"mappings":"AAAA;;;GAGG;;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AACtC,OAAO,EAA0B,gBAAgB,EAAE,MAAM,oCAAoC,CAAC;AAC9F,OAAO,EACH,YAAY,EACZ,YAAY,EACZ,mBAAmB,EACnB,gBAAgB,EAChB,QAAQ,EACR,SAAS,EACT,YAAY,EACZ,mBAAmB,
|
|
1
|
+
{"version":3,"file":"containerRuntime.d.ts","sourceRoot":"","sources":["../src/containerRuntime.ts"],"names":[],"mappings":"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"}
|
package/dist/containerRuntime.js
CHANGED
|
@@ -97,13 +97,16 @@ function unpackRuntimeMessage(message) {
|
|
|
97
97
|
return message;
|
|
98
98
|
}
|
|
99
99
|
exports.unpackRuntimeMessage = unpackRuntimeMessage;
|
|
100
|
-
|
|
101
|
-
|
|
100
|
+
/**
|
|
101
|
+
* This class controls pausing and resuming of inbound queue to ensure that we never
|
|
102
|
+
* start processing ops in a batch IF we do not have all ops in the batch.
|
|
103
|
+
*/
|
|
104
|
+
class ScheduleManagerCore {
|
|
105
|
+
constructor(deltaManager, logger) {
|
|
102
106
|
this.deltaManager = deltaManager;
|
|
103
|
-
this.emitter = emitter;
|
|
104
107
|
this.logger = logger;
|
|
105
108
|
this.localPaused = false;
|
|
106
|
-
this.
|
|
109
|
+
this.timePaused = 0;
|
|
107
110
|
// Listen for delta manager sends and add batch metadata to messages
|
|
108
111
|
this.deltaManager.on("prepareSend", (messages) => {
|
|
109
112
|
if (messages.length === 0) {
|
|
@@ -111,7 +114,7 @@ class ScheduleManager {
|
|
|
111
114
|
}
|
|
112
115
|
// First message will have the batch flag set to true if doing a batched send
|
|
113
116
|
const firstMessageMetadata = messages[0].metadata;
|
|
114
|
-
if (!firstMessageMetadata ||
|
|
117
|
+
if (!(firstMessageMetadata === null || firstMessageMetadata === void 0 ? void 0 : firstMessageMetadata.batch)) {
|
|
115
118
|
return;
|
|
116
119
|
}
|
|
117
120
|
// If the batch contains only a single op, clear the batch flag.
|
|
@@ -126,29 +129,143 @@ class ScheduleManager {
|
|
|
126
129
|
// Listen for updates and peek at the inbound
|
|
127
130
|
this.deltaManager.inbound.on("push", (message) => {
|
|
128
131
|
this.trackPending(message);
|
|
129
|
-
this.updatePauseState(message.sequenceNumber);
|
|
130
132
|
});
|
|
133
|
+
// Start with baseline - empty inbound queue.
|
|
134
|
+
common_utils_1.assert(!this.localPaused, 0x293 /* "initial state" */);
|
|
131
135
|
const allPending = this.deltaManager.inbound.toArray();
|
|
132
136
|
for (const pending of allPending) {
|
|
133
137
|
this.trackPending(pending);
|
|
134
138
|
}
|
|
135
|
-
// Based on track pending update the pause state
|
|
136
|
-
this.updatePauseState(this.deltaManager.lastSequenceNumber);
|
|
137
139
|
}
|
|
138
|
-
|
|
140
|
+
/**
|
|
141
|
+
* The only public function in this class - called when we processed an op,
|
|
142
|
+
* to make decision if op processing should be paused or not afer that.
|
|
143
|
+
*/
|
|
144
|
+
afterOpProcessing(sequenceNumber) {
|
|
145
|
+
common_utils_1.assert(!this.localPaused, 0x294 /* "can't have op processing paused if we are processing an op" */);
|
|
146
|
+
// If the inbound queue is ever empty, nothing to do!
|
|
147
|
+
if (this.deltaManager.inbound.length === 0) {
|
|
148
|
+
common_utils_1.assert(this.pauseSequenceNumber === undefined, 0x295 /* "there should be no pending batch if we have no ops" */);
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
// The queue is
|
|
152
|
+
// 1. paused only when the next message to be processed is the beginning of a batch. Done in two places:
|
|
153
|
+
// - here (processing ops until reaching start of incomplete batch)
|
|
154
|
+
// - in trackPending(), when queue was empty and start of batch showed up.
|
|
155
|
+
// 2. resumed when batch end comes in (in trackPending())
|
|
156
|
+
// do we have incomplete batch to worry about?
|
|
157
|
+
if (this.pauseSequenceNumber !== undefined) {
|
|
158
|
+
common_utils_1.assert(sequenceNumber < this.pauseSequenceNumber, 0x296 /* "we should never start processing incomplete batch!" */);
|
|
159
|
+
// If the next op is the start of incomplete batch, then we can't process it until it's fully in - pause!
|
|
160
|
+
if (sequenceNumber + 1 === this.pauseSequenceNumber) {
|
|
161
|
+
this.pauseQueue();
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
pauseQueue() {
|
|
166
|
+
common_utils_1.assert(!this.localPaused, 0x297 /* "always called from resumed state" */);
|
|
167
|
+
this.localPaused = true;
|
|
168
|
+
this.timePaused = common_utils_1.performance.now();
|
|
169
|
+
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
|
170
|
+
this.deltaManager.inbound.pause();
|
|
171
|
+
}
|
|
172
|
+
resumeQueue(startBatch, endBatch) {
|
|
173
|
+
// Return early if no change in value
|
|
174
|
+
if (!this.localPaused) {
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
this.localPaused = false;
|
|
178
|
+
const duration = common_utils_1.performance.now() - this.timePaused;
|
|
179
|
+
// Random round number - we want to know when batch waiting paused op processing.
|
|
180
|
+
if (duration > connectionTelemetry_1.latencyThreshold) {
|
|
181
|
+
this.logger.sendErrorEvent({
|
|
182
|
+
eventName: "MaxBatchWaitTimeExceeded",
|
|
183
|
+
duration,
|
|
184
|
+
sequenceNumber: endBatch,
|
|
185
|
+
length: endBatch - startBatch,
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
this.deltaManager.inbound.resume();
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Called for each incoming op (i.e. inbound "push" notification)
|
|
192
|
+
*/
|
|
193
|
+
trackPending(message) {
|
|
194
|
+
common_utils_1.assert(this.deltaManager.inbound.length !== 0, 0x298 /* "we have something in the queue that generates this event" */);
|
|
195
|
+
common_utils_1.assert((this.currentBatchClientId === undefined) === (this.pauseSequenceNumber === undefined), 0x299 /* "non-synchronized state" */);
|
|
196
|
+
const metadata = message.metadata;
|
|
197
|
+
const batchMetadata = metadata === null || metadata === void 0 ? void 0 : metadata.batch;
|
|
198
|
+
// Protocol messages are never part of a runtime batch of messages
|
|
199
|
+
if (!isRuntimeMessage(message)) {
|
|
200
|
+
// Protocol messages should never show up in the middle of the batch!
|
|
201
|
+
common_utils_1.assert(this.currentBatchClientId === undefined, 0x29a /* "System message in the middle of batch!" */);
|
|
202
|
+
common_utils_1.assert(batchMetadata === undefined, 0x29b /* "system op in a batch?" */);
|
|
203
|
+
common_utils_1.assert(!this.localPaused, 0x29c /* "we should be processing ops when there is no active batch" */);
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
if (this.currentBatchClientId === undefined && batchMetadata === undefined) {
|
|
207
|
+
common_utils_1.assert(!this.localPaused, 0x29d /* "we should be processing ops when there is no active batch" */);
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
// If the client ID changes then we can move the pause point. If it stayed the same then we need to check.
|
|
211
|
+
// If batchMetadata is not undefined then if it's true we've begun a new batch - if false we've ended
|
|
212
|
+
// the previous one
|
|
213
|
+
if (this.currentBatchClientId !== undefined || batchMetadata === false) {
|
|
214
|
+
if (this.currentBatchClientId !== message.clientId) {
|
|
215
|
+
// "Batch not closed, yet message from another client!"
|
|
216
|
+
throw new container_utils_1.DataCorruptionError("OpBatchIncomplete", Object.assign({ batchClientId: this.currentBatchClientId }, container_utils_1.extractSafePropertiesFromMessage(message)));
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
// The queue is
|
|
220
|
+
// 1. paused only when the next message to be processed is the beginning of a batch. Done in two places:
|
|
221
|
+
// - in afterOpProcessing() - processing ops until reaching start of incomplete batch
|
|
222
|
+
// - here (batchMetadata == false below), when queue was empty and start of batch showed up.
|
|
223
|
+
// 2. resumed when batch end comes in (batchMetadata === true case below)
|
|
224
|
+
if (batchMetadata) {
|
|
225
|
+
common_utils_1.assert(this.currentBatchClientId === undefined, 0x29e /* "there can't be active batch" */);
|
|
226
|
+
common_utils_1.assert(!this.localPaused, 0x29f /* "we should be processing ops when there is no active batch" */);
|
|
227
|
+
this.pauseSequenceNumber = message.sequenceNumber;
|
|
228
|
+
this.currentBatchClientId = message.clientId;
|
|
229
|
+
// Start of the batch
|
|
230
|
+
// Only pause processing if queue has no other ops!
|
|
231
|
+
// If there are any other ops in the queue, processing will be stopped when they are processed!
|
|
232
|
+
if (this.deltaManager.inbound.length === 1) {
|
|
233
|
+
this.pauseQueue();
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
else if (batchMetadata === false) {
|
|
237
|
+
common_utils_1.assert(this.pauseSequenceNumber !== undefined, 0x2a0 /* "batch presence was validated above" */);
|
|
238
|
+
// Batch is complete, we can process it!
|
|
239
|
+
this.resumeQueue(this.pauseSequenceNumber, message.sequenceNumber);
|
|
240
|
+
this.pauseSequenceNumber = undefined;
|
|
241
|
+
this.currentBatchClientId = undefined;
|
|
242
|
+
}
|
|
243
|
+
else {
|
|
244
|
+
// Continuation of current batch. Do nothing
|
|
245
|
+
common_utils_1.assert(this.currentBatchClientId !== undefined, 0x2a1 /* "logic error" */);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
/**
|
|
250
|
+
* This class has the following responsibilities:
|
|
251
|
+
* 1. It tracks batches as we process ops and raises "batchBegin" and "batchEnd" events.
|
|
252
|
+
* As part of it, it validates batch correctness (i.e. no system ops in the middle of batch)
|
|
253
|
+
* 2. It creates instance of ScheduleManagerCore that ensures we never start processing ops from batch
|
|
254
|
+
* unless all ops of the batch are in.
|
|
255
|
+
*/
|
|
256
|
+
class ScheduleManager {
|
|
257
|
+
constructor(deltaManager, emitter, logger) {
|
|
258
|
+
this.deltaManager = deltaManager;
|
|
259
|
+
this.emitter = emitter;
|
|
260
|
+
this.logger = logger;
|
|
261
|
+
this.hitError = false;
|
|
262
|
+
this.deltaScheduler = new deltaScheduler_1.DeltaScheduler(this.deltaManager, telemetry_utils_1.ChildLogger.create(this.logger, "DeltaScheduler"));
|
|
263
|
+
this.scheduler = new ScheduleManagerCore(deltaManager, logger);
|
|
264
|
+
}
|
|
265
|
+
beforeOpProcessing(message) {
|
|
139
266
|
var _a;
|
|
140
267
|
if (this.batchClientId !== message.clientId) {
|
|
141
|
-
|
|
142
|
-
// consider the previous batch over.
|
|
143
|
-
if (this.batchClientId) {
|
|
144
|
-
this.emitter.emit("batchEnd", "Did not receive real batchEnd message", undefined);
|
|
145
|
-
this.deltaScheduler.batchEnd();
|
|
146
|
-
this.logger.sendTelemetryEvent({
|
|
147
|
-
eventName: "BatchEndNotReceived",
|
|
148
|
-
clientId: this.batchClientId,
|
|
149
|
-
sequenceNumber: message.sequenceNumber,
|
|
150
|
-
});
|
|
151
|
-
}
|
|
268
|
+
common_utils_1.assert(this.batchClientId === undefined, 0x2a2 /* "Batch is interrupted by other client op. Should be caught by trackPending()" */);
|
|
152
269
|
// This could be the beginning of a new batch or an individual message.
|
|
153
270
|
this.emitter.emit("batchBegin", message);
|
|
154
271
|
this.deltaScheduler.batchBegin();
|
|
@@ -161,79 +278,32 @@ class ScheduleManager {
|
|
|
161
278
|
}
|
|
162
279
|
}
|
|
163
280
|
}
|
|
164
|
-
|
|
281
|
+
afterOpProcessing(error, message) {
|
|
165
282
|
var _a;
|
|
283
|
+
// If this is no longer true, we need to revisit what we do where we set this.hitError.
|
|
284
|
+
common_utils_1.assert(!this.hitError, 0x2a3 /* "container should be closed on any error" */);
|
|
285
|
+
// Let the scheduler know how far we progressed, to decide if op processing
|
|
286
|
+
// should be paused or not.
|
|
287
|
+
this.scheduler.afterOpProcessing(message.sequenceNumber);
|
|
166
288
|
if (error) {
|
|
289
|
+
// We assume here that loader will close container and stop processing all future ops.
|
|
290
|
+
// This is implicit dependency. If this flow changes, this code might no longer be correct.
|
|
291
|
+
this.hitError = true;
|
|
167
292
|
this.batchClientId = undefined;
|
|
168
293
|
this.emitter.emit("batchEnd", error, message);
|
|
169
294
|
this.deltaScheduler.batchEnd();
|
|
170
295
|
return;
|
|
171
296
|
}
|
|
172
|
-
this.updatePauseState(message.sequenceNumber);
|
|
173
297
|
const batch = (_a = message === null || message === void 0 ? void 0 : message.metadata) === null || _a === void 0 ? void 0 : _a.batch;
|
|
174
298
|
// If no batchClientId has been set then we're in an individual batch. Else, if we get
|
|
175
299
|
// batch end metadata, this is end of the current batch.
|
|
176
|
-
if (
|
|
300
|
+
if (this.batchClientId === undefined || batch === false) {
|
|
177
301
|
this.batchClientId = undefined;
|
|
178
302
|
this.emitter.emit("batchEnd", undefined, message);
|
|
179
303
|
this.deltaScheduler.batchEnd();
|
|
180
304
|
return;
|
|
181
305
|
}
|
|
182
306
|
}
|
|
183
|
-
setPaused(localPaused) {
|
|
184
|
-
// Return early if no change in value
|
|
185
|
-
if (this.localPaused === localPaused) {
|
|
186
|
-
return;
|
|
187
|
-
}
|
|
188
|
-
this.localPaused = localPaused;
|
|
189
|
-
if (localPaused) {
|
|
190
|
-
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
|
191
|
-
this.deltaManager.inbound.pause();
|
|
192
|
-
}
|
|
193
|
-
else {
|
|
194
|
-
this.deltaManager.inbound.resume();
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
updatePauseState(sequenceNumber) {
|
|
198
|
-
// If the inbound queue is ever empty we pause it and wait for new events
|
|
199
|
-
if (this.deltaManager.inbound.length === 0) {
|
|
200
|
-
this.setPaused(true);
|
|
201
|
-
return;
|
|
202
|
-
}
|
|
203
|
-
// If no message has caused the pause flag to be set, or the next message up is not the one we need to pause at
|
|
204
|
-
// then we simply continue processing
|
|
205
|
-
if (!this.pauseSequenceNumber || sequenceNumber + 1 < this.pauseSequenceNumber) {
|
|
206
|
-
this.setPaused(false);
|
|
207
|
-
}
|
|
208
|
-
else {
|
|
209
|
-
// Otherwise the next message requires us to pause
|
|
210
|
-
this.setPaused(true);
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
trackPending(message) {
|
|
214
|
-
const metadata = message.metadata;
|
|
215
|
-
// Protocol messages are never part of a runtime batch of messages
|
|
216
|
-
if (!isRuntimeMessage(message)) {
|
|
217
|
-
this.pauseSequenceNumber = undefined;
|
|
218
|
-
this.pauseClientId = undefined;
|
|
219
|
-
return;
|
|
220
|
-
}
|
|
221
|
-
const batchMetadata = metadata ? metadata.batch : undefined;
|
|
222
|
-
// If the client ID changes then we can move the pause point. If it stayed the same then we need to check.
|
|
223
|
-
if (this.pauseClientId === message.clientId) {
|
|
224
|
-
if (batchMetadata !== undefined) {
|
|
225
|
-
// If batchMetadata is not undefined then if it's true we've begun a new batch - if false we've ended
|
|
226
|
-
// the previous one
|
|
227
|
-
this.pauseSequenceNumber = batchMetadata ? message.sequenceNumber : undefined;
|
|
228
|
-
this.pauseClientId = batchMetadata ? this.pauseClientId : undefined;
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
else {
|
|
232
|
-
// We check the batch flag for the new clientID - if true we pause otherwise we reset the tracking data
|
|
233
|
-
this.pauseSequenceNumber = batchMetadata ? message.sequenceNumber : undefined;
|
|
234
|
-
this.pauseClientId = batchMetadata ? message.clientId : undefined;
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
307
|
}
|
|
238
308
|
exports.ScheduleManager = ScheduleManager;
|
|
239
309
|
/**
|
|
@@ -305,9 +375,9 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
|
|
|
305
375
|
}
|
|
306
376
|
else {
|
|
307
377
|
// If we're not the summarizer, and we don't have a summaryManager, we expect that
|
|
308
|
-
//
|
|
378
|
+
// disableSummaries is turned on. We are throwing instead of returning a failure here,
|
|
309
379
|
// because it is a misuse of the API rather than an expected failure.
|
|
310
|
-
throw new Error(`Can't summarize,
|
|
380
|
+
throw new Error(`Can't summarize, disableSummaries: ${this.summariesDisabled()}`);
|
|
311
381
|
}
|
|
312
382
|
};
|
|
313
383
|
this.enqueueSummarize = (...args) => {
|
|
@@ -321,7 +391,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
|
|
|
321
391
|
// If we're not the summarizer, and we don't have a summaryManager, we expect that
|
|
322
392
|
// generateSummaries is turned off. We are throwing instead of returning a failure here,
|
|
323
393
|
// because it is a misuse of the API rather than an expected failure.
|
|
324
|
-
throw new Error(`Can't summarize,
|
|
394
|
+
throw new Error(`Can't summarize, disableSummaries: ${this.summariesDisabled()}`);
|
|
325
395
|
}
|
|
326
396
|
};
|
|
327
397
|
this.baseSummaryMessage = metadata === null || metadata === void 0 ? void 0 : metadata.message;
|
|
@@ -370,7 +440,11 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
|
|
|
370
440
|
});
|
|
371
441
|
this.summaryCollection = new summaryCollection_1.SummaryCollection(this.deltaManager, this.logger);
|
|
372
442
|
// Only create a SummaryManager if summaries are enabled and we are not the summarizer client
|
|
443
|
+
// Map the deprecated generateSummaries flag to disableSummaries.
|
|
373
444
|
if (this.runtimeOptions.summaryOptions.generateSummaries === false) {
|
|
445
|
+
this.runtimeOptions.summaryOptions.disableSummaries = true;
|
|
446
|
+
}
|
|
447
|
+
if (this.summariesDisabled()) {
|
|
374
448
|
this._logger.sendTelemetryEvent({ eventName: "SummariesDisabled" });
|
|
375
449
|
}
|
|
376
450
|
else {
|
|
@@ -460,7 +534,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
|
|
|
460
534
|
runtimeVersion: packageVersion_1.pkgVersion,
|
|
461
535
|
},
|
|
462
536
|
});
|
|
463
|
-
const { summaryOptions = {
|
|
537
|
+
const { summaryOptions = {}, gcOptions = {}, loadSequenceNumberVerification = "close", } = runtimeOptions;
|
|
464
538
|
// We pack at data store level only. If isolated channels are disabled,
|
|
465
539
|
// then there are no .channel layers, we pack at level 1, otherwise we pack at level 2
|
|
466
540
|
const packingLevel = summaryOptions.disableIsolatedChannels ? 1 : 2;
|
|
@@ -511,7 +585,8 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
|
|
|
511
585
|
const protocolSequenceNumber = context.deltaManager.initialSequenceNumber;
|
|
512
586
|
// Unless bypass is explicitly set, then take action when sequence numbers mismatch.
|
|
513
587
|
if (loadSequenceNumberVerification !== "bypass" && runtimeSequenceNumber !== protocolSequenceNumber) {
|
|
514
|
-
|
|
588
|
+
// "Load from summary, runtime metadata sequenceNumber !== initialSequenceNumber"
|
|
589
|
+
const error = new container_utils_1.DataCorruptionError("SummaryMetadataMismatch", { runtimeSequenceNumber, protocolSequenceNumber });
|
|
515
590
|
if (loadSequenceNumberVerification === "log") {
|
|
516
591
|
logger.sendErrorEvent({ eventName: "SequenceNumberMismatch" }, error);
|
|
517
592
|
}
|
|
@@ -848,11 +923,10 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
|
|
|
848
923
|
// We do not need to make deep copy, as each layer will just replace message.content itself,
|
|
849
924
|
// but would not modify contents details
|
|
850
925
|
let message = Object.assign({}, messageArg);
|
|
851
|
-
let error;
|
|
852
926
|
// Surround the actual processing of the operation with messages to the schedule manager indicating
|
|
853
927
|
// the beginning and end. This allows it to emit appropriate events and/or pause the processing of new
|
|
854
928
|
// messages once a batch has been fully processed.
|
|
855
|
-
this.scheduleManager.
|
|
929
|
+
this.scheduleManager.beforeOpProcessing(message);
|
|
856
930
|
try {
|
|
857
931
|
message = unpackRuntimeMessage(message);
|
|
858
932
|
// Chunk processing must come first given that we will transform the message to the unchunked version
|
|
@@ -880,14 +954,12 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
|
|
|
880
954
|
default:
|
|
881
955
|
}
|
|
882
956
|
this.emit("op", message);
|
|
957
|
+
this.scheduleManager.afterOpProcessing(undefined, message);
|
|
883
958
|
}
|
|
884
959
|
catch (e) {
|
|
885
|
-
|
|
960
|
+
this.scheduleManager.afterOpProcessing(e, message);
|
|
886
961
|
throw e;
|
|
887
962
|
}
|
|
888
|
-
finally {
|
|
889
|
-
this.scheduleManager.endOperation(error, message);
|
|
890
|
-
}
|
|
891
963
|
}
|
|
892
964
|
processSignal(message, local) {
|
|
893
965
|
const envelope = message.content;
|
|
@@ -974,7 +1046,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
|
|
|
974
1046
|
}
|
|
975
1047
|
async createRootDataStore(pkg, rootDataStoreId) {
|
|
976
1048
|
const fluidDataStore = await this._createDataStore(pkg, true /* isRoot */, rootDataStoreId);
|
|
977
|
-
fluidDataStore.
|
|
1049
|
+
fluidDataStore.bindToContext();
|
|
978
1050
|
return fluidDataStore;
|
|
979
1051
|
}
|
|
980
1052
|
createDetachedRootDataStore(pkg, rootDataStoreId) {
|
|
@@ -986,7 +1058,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
|
|
|
986
1058
|
async _createDataStoreWithProps(pkg, props, id = uuid_1.v4(), isRoot = false) {
|
|
987
1059
|
const fluidDataStore = await this.dataStores._createFluidDataStoreContext(Array.isArray(pkg) ? pkg : [pkg], id, isRoot, props).realize();
|
|
988
1060
|
if (isRoot) {
|
|
989
|
-
fluidDataStore.
|
|
1061
|
+
fluidDataStore.bindToContext();
|
|
990
1062
|
}
|
|
991
1063
|
return fluidDataStore;
|
|
992
1064
|
}
|
|
@@ -1099,7 +1171,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
|
|
|
1099
1171
|
await this.collectGarbage({ logger: summaryLogger, runSweep, fullGC });
|
|
1100
1172
|
}
|
|
1101
1173
|
const summarizeResult = await this.summarizerNode.summarize(fullTree, trackState);
|
|
1102
|
-
common_utils_1.assert(summarizeResult.summary.type ===
|
|
1174
|
+
common_utils_1.assert(summarizeResult.summary.type === protocol_definitions_1.SummaryType.Tree, 0x12f /* "Container Runtime's summarize should always return a tree" */);
|
|
1103
1175
|
return summarizeResult;
|
|
1104
1176
|
}
|
|
1105
1177
|
/**
|
|
@@ -1215,8 +1287,8 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
|
|
|
1215
1287
|
// Because handles are unchanged dataStores in the current logic,
|
|
1216
1288
|
// summarized dataStore count is total dataStore count minus handle count
|
|
1217
1289
|
const dataStoreTree = this.disableIsolatedChannels ? summaryTree : summaryTree.tree[runtime_definitions_1.channelsTreeName];
|
|
1218
|
-
common_utils_1.assert(dataStoreTree.type ===
|
|
1219
|
-
const handleCount = Object.values(dataStoreTree.tree).filter((value) => value.type ===
|
|
1290
|
+
common_utils_1.assert(dataStoreTree.type === protocol_definitions_1.SummaryType.Tree, 0x1fc /* "summary is not a tree" */);
|
|
1291
|
+
const handleCount = Object.values(dataStoreTree.tree).filter((value) => value.type === protocol_definitions_1.SummaryType.Handle).length;
|
|
1220
1292
|
const summaryStats = Object.assign({ dataStoreCount: this.dataStores.size, summarizedDataStoreCount: this.dataStores.size - handleCount }, partialStats);
|
|
1221
1293
|
const generateSummaryData = {
|
|
1222
1294
|
referenceSequenceNumber: summaryRefSeqNum,
|
|
@@ -1493,6 +1565,14 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
|
|
|
1493
1565
|
getPendingLocalState() {
|
|
1494
1566
|
return this.pendingStateManager.getLocalState();
|
|
1495
1567
|
}
|
|
1568
|
+
/**
|
|
1569
|
+
* @returns true if summaries are explicitly disabled for this ContainerRuntime, false otherwise
|
|
1570
|
+
*/
|
|
1571
|
+
summariesDisabled() {
|
|
1572
|
+
var _a;
|
|
1573
|
+
return this.runtimeOptions.summaryOptions.disableSummaries === true ||
|
|
1574
|
+
((_a = this.runtimeOptions.summaryOptions.summaryConfigOverrides) === null || _a === void 0 ? void 0 : _a.disableSummaries) === true;
|
|
1575
|
+
}
|
|
1496
1576
|
}
|
|
1497
1577
|
exports.ContainerRuntime = ContainerRuntime;
|
|
1498
1578
|
/**
|