@fluidframework/container-runtime 2.0.0-internal.7.0.0 → 2.0.0-internal.7.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 +12 -0
- package/api-extractor.json +1 -1
- package/api-report/container-runtime.api.md +864 -0
- package/dist/blobManager.d.ts +4 -6
- package/dist/blobManager.d.ts.map +1 -1
- package/dist/blobManager.js +42 -56
- package/dist/blobManager.js.map +1 -1
- package/dist/connectionTelemetry.d.ts.map +1 -1
- package/dist/connectionTelemetry.js +75 -42
- package/dist/connectionTelemetry.js.map +1 -1
- package/dist/containerRuntime.d.ts +90 -36
- package/dist/containerRuntime.d.ts.map +1 -1
- package/dist/containerRuntime.js +125 -59
- package/dist/containerRuntime.js.map +1 -1
- package/dist/dataStore.js +2 -2
- package/dist/dataStore.js.map +1 -1
- package/dist/dataStoreContext.d.ts +8 -2
- package/dist/dataStoreContext.d.ts.map +1 -1
- package/dist/dataStoreContext.js +15 -8
- package/dist/dataStoreContext.js.map +1 -1
- package/dist/dataStoreRegistry.d.ts +3 -0
- package/dist/dataStoreRegistry.d.ts.map +1 -1
- package/dist/dataStoreRegistry.js +3 -0
- package/dist/dataStoreRegistry.js.map +1 -1
- package/dist/dataStores.d.ts +0 -2
- package/dist/dataStores.d.ts.map +1 -1
- package/dist/dataStores.js +2 -7
- package/dist/dataStores.js.map +1 -1
- package/dist/deltaManagerProxyBase.d.ts +1 -1
- package/dist/deltaManagerProxyBase.d.ts.map +1 -1
- package/dist/deltaManagerProxyBase.js +2 -2
- package/dist/deltaManagerProxyBase.js.map +1 -1
- package/dist/error.d.ts.map +1 -1
- package/dist/error.js.map +1 -1
- package/dist/gc/garbageCollection.d.ts +6 -0
- package/dist/gc/garbageCollection.d.ts.map +1 -1
- package/dist/gc/garbageCollection.js +16 -3
- package/dist/gc/garbageCollection.js.map +1 -1
- package/dist/gc/gcConfigs.d.ts +1 -0
- package/dist/gc/gcConfigs.d.ts.map +1 -1
- package/dist/gc/gcConfigs.js +12 -2
- package/dist/gc/gcConfigs.js.map +1 -1
- package/dist/gc/gcDefinitions.d.ts +42 -11
- package/dist/gc/gcDefinitions.d.ts.map +1 -1
- package/dist/gc/gcDefinitions.js +4 -1
- package/dist/gc/gcDefinitions.js.map +1 -1
- package/dist/gc/gcSummaryDefinitions.d.ts +1 -1
- package/dist/gc/gcSummaryDefinitions.js.map +1 -1
- package/dist/gc/gcTelemetry.d.ts +2 -3
- package/dist/gc/gcTelemetry.d.ts.map +1 -1
- package/dist/gc/gcTelemetry.js +7 -8
- package/dist/gc/gcTelemetry.js.map +1 -1
- package/dist/gc/index.d.ts +2 -2
- package/dist/gc/index.d.ts.map +1 -1
- package/dist/gc/index.js +1 -5
- package/dist/gc/index.js.map +1 -1
- package/dist/id-compressor/utilities.d.ts +3 -0
- package/dist/id-compressor/utilities.d.ts.map +1 -1
- package/dist/id-compressor/utilities.js +3 -0
- package/dist/id-compressor/utilities.js.map +1 -1
- package/dist/index.d.ts +4 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -1
- package/dist/index.js.map +1 -1
- package/dist/messageTypes.d.ts +4 -1
- package/dist/messageTypes.d.ts.map +1 -1
- package/dist/messageTypes.js +3 -0
- package/dist/messageTypes.js.map +1 -1
- package/dist/opLifecycle/definitions.d.ts +3 -0
- package/dist/opLifecycle/definitions.d.ts.map +1 -1
- package/dist/opLifecycle/definitions.js.map +1 -1
- package/dist/opLifecycle/outbox.d.ts.map +1 -1
- package/dist/opLifecycle/outbox.js +7 -2
- 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.map +1 -1
- package/dist/pendingStateManager.js +3 -1
- package/dist/pendingStateManager.js.map +1 -1
- package/dist/scheduleManager.js +6 -2
- package/dist/scheduleManager.js.map +1 -1
- package/dist/summary/orderedClientElection.d.ts +4 -1
- package/dist/summary/orderedClientElection.d.ts.map +1 -1
- package/dist/summary/orderedClientElection.js.map +1 -1
- package/dist/summary/runWhileConnectedCoordinator.d.ts +5 -0
- package/dist/summary/runWhileConnectedCoordinator.d.ts.map +1 -1
- package/dist/summary/runWhileConnectedCoordinator.js +1 -0
- package/dist/summary/runWhileConnectedCoordinator.js.map +1 -1
- package/dist/summary/summarizer.d.ts +2 -0
- package/dist/summary/summarizer.d.ts.map +1 -1
- package/dist/summary/summarizer.js +15 -7
- package/dist/summary/summarizer.js.map +1 -1
- package/dist/summary/summarizerTypes.d.ts +94 -10
- package/dist/summary/summarizerTypes.d.ts.map +1 -1
- package/dist/summary/summarizerTypes.js.map +1 -1
- package/dist/summary/summaryCollection.d.ts +16 -0
- package/dist/summary/summaryCollection.d.ts.map +1 -1
- package/dist/summary/summaryCollection.js +2 -0
- package/dist/summary/summaryCollection.js.map +1 -1
- package/dist/summary/summaryFormat.d.ts +10 -1
- package/dist/summary/summaryFormat.d.ts.map +1 -1
- package/dist/summary/summaryFormat.js.map +1 -1
- package/dist/summary/summaryGenerator.js.map +1 -1
- package/dist/summary/summaryManager.d.ts +2 -2
- package/dist/summary/summaryManager.d.ts.map +1 -1
- package/dist/summary/summaryManager.js +3 -3
- package/dist/summary/summaryManager.js.map +1 -1
- package/dist/tsdoc-metadata.json +1 -1
- package/lib/blobManager.d.ts +4 -6
- package/lib/blobManager.d.ts.map +1 -1
- package/lib/blobManager.js +44 -58
- package/lib/blobManager.js.map +1 -1
- package/lib/connectionTelemetry.d.ts.map +1 -1
- package/lib/connectionTelemetry.js +76 -43
- package/lib/connectionTelemetry.js.map +1 -1
- package/lib/containerRuntime.d.ts +90 -36
- package/lib/containerRuntime.d.ts.map +1 -1
- package/lib/containerRuntime.js +125 -62
- package/lib/containerRuntime.js.map +1 -1
- package/lib/dataStore.js +2 -2
- package/lib/dataStore.js.map +1 -1
- package/lib/dataStoreContext.d.ts +8 -2
- package/lib/dataStoreContext.d.ts.map +1 -1
- package/lib/dataStoreContext.js +16 -9
- package/lib/dataStoreContext.js.map +1 -1
- package/lib/dataStoreRegistry.d.ts +3 -0
- package/lib/dataStoreRegistry.d.ts.map +1 -1
- package/lib/dataStoreRegistry.js +3 -0
- package/lib/dataStoreRegistry.js.map +1 -1
- package/lib/dataStores.d.ts +0 -2
- package/lib/dataStores.d.ts.map +1 -1
- package/lib/dataStores.js +3 -8
- package/lib/dataStores.js.map +1 -1
- package/lib/deltaManagerProxyBase.d.ts +1 -1
- package/lib/deltaManagerProxyBase.d.ts.map +1 -1
- package/lib/deltaManagerProxyBase.js +2 -2
- package/lib/deltaManagerProxyBase.js.map +1 -1
- package/lib/error.d.ts.map +1 -1
- package/lib/error.js.map +1 -1
- package/lib/gc/garbageCollection.d.ts +6 -0
- package/lib/gc/garbageCollection.d.ts.map +1 -1
- package/lib/gc/garbageCollection.js +16 -3
- package/lib/gc/garbageCollection.js.map +1 -1
- package/lib/gc/gcConfigs.d.ts +1 -0
- package/lib/gc/gcConfigs.d.ts.map +1 -1
- package/lib/gc/gcConfigs.js +14 -4
- package/lib/gc/gcConfigs.js.map +1 -1
- package/lib/gc/gcDefinitions.d.ts +42 -11
- package/lib/gc/gcDefinitions.d.ts.map +1 -1
- package/lib/gc/gcDefinitions.js +4 -1
- package/lib/gc/gcDefinitions.js.map +1 -1
- package/lib/gc/gcSummaryDefinitions.d.ts +1 -1
- package/lib/gc/gcSummaryDefinitions.js.map +1 -1
- package/lib/gc/gcTelemetry.d.ts +2 -3
- package/lib/gc/gcTelemetry.d.ts.map +1 -1
- package/lib/gc/gcTelemetry.js +7 -8
- package/lib/gc/gcTelemetry.js.map +1 -1
- package/lib/gc/index.d.ts +2 -2
- package/lib/gc/index.d.ts.map +1 -1
- package/lib/gc/index.js +2 -2
- package/lib/gc/index.js.map +1 -1
- package/lib/id-compressor/utilities.d.ts +3 -0
- package/lib/id-compressor/utilities.d.ts.map +1 -1
- package/lib/id-compressor/utilities.js +3 -0
- package/lib/id-compressor/utilities.js.map +1 -1
- package/lib/index.d.ts +4 -3
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +2 -1
- package/lib/index.js.map +1 -1
- package/lib/messageTypes.d.ts +4 -1
- package/lib/messageTypes.d.ts.map +1 -1
- package/lib/messageTypes.js +3 -0
- package/lib/messageTypes.js.map +1 -1
- package/lib/opLifecycle/definitions.d.ts +3 -0
- package/lib/opLifecycle/definitions.d.ts.map +1 -1
- package/lib/opLifecycle/definitions.js.map +1 -1
- package/lib/opLifecycle/outbox.d.ts.map +1 -1
- package/lib/opLifecycle/outbox.js +7 -2
- 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.map +1 -1
- package/lib/pendingStateManager.js +3 -1
- package/lib/pendingStateManager.js.map +1 -1
- package/lib/scheduleManager.js +6 -2
- package/lib/scheduleManager.js.map +1 -1
- package/lib/summary/orderedClientElection.d.ts +4 -1
- package/lib/summary/orderedClientElection.d.ts.map +1 -1
- package/lib/summary/orderedClientElection.js.map +1 -1
- package/lib/summary/runWhileConnectedCoordinator.d.ts +5 -0
- package/lib/summary/runWhileConnectedCoordinator.d.ts.map +1 -1
- package/lib/summary/runWhileConnectedCoordinator.js +1 -0
- package/lib/summary/runWhileConnectedCoordinator.js.map +1 -1
- package/lib/summary/summarizer.d.ts +2 -0
- package/lib/summary/summarizer.d.ts.map +1 -1
- package/lib/summary/summarizer.js +16 -8
- package/lib/summary/summarizer.js.map +1 -1
- package/lib/summary/summarizerTypes.d.ts +94 -10
- package/lib/summary/summarizerTypes.d.ts.map +1 -1
- package/lib/summary/summarizerTypes.js.map +1 -1
- package/lib/summary/summaryCollection.d.ts +16 -0
- package/lib/summary/summaryCollection.d.ts.map +1 -1
- package/lib/summary/summaryCollection.js +2 -0
- package/lib/summary/summaryCollection.js.map +1 -1
- package/lib/summary/summaryFormat.d.ts +10 -1
- package/lib/summary/summaryFormat.d.ts.map +1 -1
- package/lib/summary/summaryFormat.js.map +1 -1
- package/lib/summary/summaryGenerator.js.map +1 -1
- package/lib/summary/summaryManager.d.ts +2 -2
- package/lib/summary/summaryManager.d.ts.map +1 -1
- package/lib/summary/summaryManager.js +3 -3
- package/lib/summary/summaryManager.js.map +1 -1
- package/package.json +26 -58
- package/src/blobManager.ts +61 -74
- package/src/connectionTelemetry.ts +97 -52
- package/src/containerRuntime.ts +173 -93
- package/src/dataStore.ts +2 -2
- package/src/dataStoreContext.ts +16 -9
- package/src/dataStoreRegistry.ts +3 -0
- package/src/dataStores.ts +4 -16
- package/src/deltaManagerProxyBase.ts +2 -2
- package/src/error.ts +4 -1
- package/src/gc/garbageCollection.ts +18 -3
- package/src/gc/gcConfigs.ts +22 -4
- package/src/gc/gcDefinitions.ts +43 -11
- package/src/gc/gcSummaryDefinitions.ts +1 -1
- package/src/gc/gcTelemetry.ts +8 -8
- package/src/gc/index.ts +0 -4
- package/src/id-compressor/utilities.ts +3 -0
- package/src/index.ts +14 -1
- package/src/messageTypes.ts +4 -1
- package/src/opLifecycle/README.md +53 -28
- package/src/opLifecycle/definitions.ts +3 -0
- package/src/opLifecycle/outbox.ts +3 -0
- package/src/packageVersion.ts +1 -1
- package/src/pendingStateManager.ts +1 -0
- package/src/scheduleManager.ts +2 -0
- package/src/summary/orderedClientElection.ts +4 -1
- package/src/summary/runWhileConnectedCoordinator.ts +5 -1
- package/src/summary/summarizer.ts +21 -9
- package/src/summary/summarizerTypes.ts +95 -11
- package/src/summary/summaryCollection.ts +19 -1
- package/src/summary/summaryFormat.ts +11 -1
- package/src/summary/summaryGenerator.ts +3 -3
- package/src/summary/summaryManager.ts +2 -2
- package/src/gc/gcEarlyAdoption.md +0 -145
|
@@ -17,16 +17,32 @@ class OpPerfTelemetry {
|
|
|
17
17
|
constructor(clientId, deltaManager, logger) {
|
|
18
18
|
this.clientId = clientId;
|
|
19
19
|
this.deltaManager = deltaManager;
|
|
20
|
-
this.pongCount = 0;
|
|
21
20
|
this.msnTrackingTimestamp = 0;
|
|
22
|
-
this.opProcessingTimes = {};
|
|
23
21
|
// Performance Data to be reported for ops round trips and processing.
|
|
24
|
-
this.
|
|
22
|
+
this.latencyStatistics = new Map();
|
|
25
23
|
this.firstConnection = true;
|
|
26
24
|
this.bootTime = client_utils_1.performance.now();
|
|
27
25
|
this.connectionStartTime = 0;
|
|
28
26
|
this.gap = 0;
|
|
29
27
|
this.logger = (0, telemetry_utils_1.createChildLogger)({ logger, namespace: "OpPerf" });
|
|
28
|
+
const deltaLatencyEventSampler = (() => {
|
|
29
|
+
let eventCount = -1;
|
|
30
|
+
return {
|
|
31
|
+
sample: () => {
|
|
32
|
+
eventCount++;
|
|
33
|
+
const shouldSample = eventCount % OpPerfTelemetry.DELTA_LATENCY_SAMPLE_RATE === 0;
|
|
34
|
+
if (shouldSample) {
|
|
35
|
+
eventCount = 0;
|
|
36
|
+
}
|
|
37
|
+
return shouldSample;
|
|
38
|
+
},
|
|
39
|
+
};
|
|
40
|
+
})();
|
|
41
|
+
this.deltaLatencyLogger = (0, telemetry_utils_1.createSampledLogger)(logger, deltaLatencyEventSampler);
|
|
42
|
+
// The SampledLogger here is used get access to the isSamplingDisabled property dervied from
|
|
43
|
+
// telemetry config properties. The actual sampling logic for op messages happens outside this SampledLogger
|
|
44
|
+
// due to complexity of the different asynchronus scenarios of the op message lifecycle.
|
|
45
|
+
this.opLatencyLogger = (0, telemetry_utils_1.createSampledLogger)(logger);
|
|
30
46
|
this.deltaManager.on("pong", (latency) => this.recordPingTime(latency));
|
|
31
47
|
this.deltaManager.on("submitOp", (message) => this.beforeOpSubmit(message));
|
|
32
48
|
this.deltaManager.on("op", (message) => this.afterProcessingOp(message));
|
|
@@ -45,38 +61,45 @@ class OpPerfTelemetry {
|
|
|
45
61
|
this.deltaManager.on("disconnect", () => {
|
|
46
62
|
this.sequenceNumberForMsnTracking = undefined;
|
|
47
63
|
this.clientSequenceNumberForLatencyStatistics = undefined;
|
|
48
|
-
this.opProcessingTimes = {};
|
|
49
|
-
this.opPerfData = {};
|
|
50
64
|
this.connectionOpSeqNumber = undefined;
|
|
51
65
|
this.firstConnection = false;
|
|
52
|
-
this.
|
|
66
|
+
this.latencyStatistics.clear();
|
|
53
67
|
});
|
|
54
68
|
this.deltaManager.outbound.on("push", (messages) => {
|
|
55
69
|
for (const msg of messages) {
|
|
56
70
|
if (msg.type === protocol_definitions_1.MessageType.Operation &&
|
|
57
|
-
this.
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
(0, core_utils_1.assert)(
|
|
62
|
-
(0, core_utils_1.assert)(
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
71
|
+
(this.opLatencyLogger.isSamplingDisabled ||
|
|
72
|
+
this.clientSequenceNumberForLatencyStatistics === msg.clientSequenceNumber)) {
|
|
73
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
74
|
+
const latencyStats = this.latencyStatistics.get(msg.clientSequenceNumber);
|
|
75
|
+
(0, core_utils_1.assert)(latencyStats !== undefined, 0x7c2 /* Latency stats for op should exist */);
|
|
76
|
+
(0, core_utils_1.assert)(latencyStats.opProcessingTimes.outboundPushEventTime === undefined, 0x2c8 /* "outboundPushEventTime should be undefined" */);
|
|
77
|
+
(0, core_utils_1.assert)(latencyStats.opPerfData.durationNetwork === undefined, 0x2c9 /* "durationNetwork should be undefined" */);
|
|
78
|
+
latencyStats.opProcessingTimes.outboundPushEventTime = Date.now();
|
|
79
|
+
(0, core_utils_1.assert)(latencyStats.opPerfData.durationOutboundBatching === undefined, 0x2ca /* "durationOutboundBatching should be undefined" */);
|
|
80
|
+
(0, core_utils_1.assert)(latencyStats.opProcessingTimes.submitOpEventTime !== undefined, 0x2cb /* "submitOpEventTime should be undefined" */);
|
|
81
|
+
latencyStats.opPerfData.durationOutboundBatching =
|
|
82
|
+
latencyStats.opProcessingTimes.outboundPushEventTime -
|
|
83
|
+
latencyStats.opProcessingTimes.submitOpEventTime;
|
|
66
84
|
}
|
|
67
85
|
}
|
|
68
86
|
});
|
|
69
87
|
this.deltaManager.inbound.on("push", (message) => {
|
|
70
88
|
if (this.clientId === message.clientId &&
|
|
71
89
|
message.type === protocol_definitions_1.MessageType.Operation &&
|
|
72
|
-
this.
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
90
|
+
(this.opLatencyLogger.isSamplingDisabled ||
|
|
91
|
+
this.clientSequenceNumberForLatencyStatistics === message.clientSequenceNumber)) {
|
|
92
|
+
// We do an explicit check for undefined right after this
|
|
93
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
94
|
+
const latencyStats = this.latencyStatistics.get(message.clientSequenceNumber);
|
|
95
|
+
(0, core_utils_1.assert)(latencyStats !== undefined, 0x7c3 /* Latency stats for op should exist */);
|
|
96
|
+
if (latencyStats.opProcessingTimes.outboundPushEventTime !== undefined) {
|
|
97
|
+
latencyStats.opProcessingTimes.inboundPushEventTime = Date.now();
|
|
98
|
+
latencyStats.opPerfData.durationNetwork =
|
|
99
|
+
latencyStats.opProcessingTimes.inboundPushEventTime -
|
|
100
|
+
latencyStats.opProcessingTimes.outboundPushEventTime;
|
|
101
|
+
latencyStats.opPerfData.lengthInboundQueue = this.deltaManager.inbound.length;
|
|
102
|
+
}
|
|
80
103
|
}
|
|
81
104
|
});
|
|
82
105
|
this.deltaManager.inbound.on("idle", (count, duration) => {
|
|
@@ -117,23 +140,27 @@ class OpPerfTelemetry {
|
|
|
117
140
|
duration: latency,
|
|
118
141
|
});
|
|
119
142
|
}
|
|
120
|
-
// logging one in every
|
|
121
|
-
if (this.
|
|
122
|
-
this.
|
|
143
|
+
// logging one in every DELTA_LATENCY_SAMPLE_RATE pongs, including the first time, if it is a "write" client.
|
|
144
|
+
if (this.deltaManager.active) {
|
|
145
|
+
this.deltaLatencyLogger.sendPerformanceEvent({
|
|
123
146
|
eventName: "DeltaLatency",
|
|
124
147
|
duration: latency,
|
|
125
148
|
});
|
|
126
149
|
}
|
|
127
|
-
this.pongCount++;
|
|
128
150
|
}
|
|
129
151
|
beforeOpSubmit(message) {
|
|
130
152
|
// start with first client op and measure latency every 500 client ops
|
|
131
|
-
if (this.
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
(0, core_utils_1.assert)(this.
|
|
135
|
-
this.opProcessingTimes.submitOpEventTime = Date.now();
|
|
153
|
+
if (this.opLatencyLogger.isSamplingDisabled ||
|
|
154
|
+
(this.clientSequenceNumberForLatencyStatistics === undefined &&
|
|
155
|
+
message.clientSequenceNumber % OpPerfTelemetry.OP_LATENCY_SAMPLE_RATE === 1)) {
|
|
156
|
+
(0, core_utils_1.assert)(this.latencyStatistics.get(message.clientSequenceNumber) === undefined, 0x7c4 /* Existing op perf data for client sequence number */);
|
|
136
157
|
this.clientSequenceNumberForLatencyStatistics = message.clientSequenceNumber;
|
|
158
|
+
this.latencyStatistics.set(message.clientSequenceNumber, {
|
|
159
|
+
opProcessingTimes: {
|
|
160
|
+
submitOpEventTime: Date.now(),
|
|
161
|
+
},
|
|
162
|
+
opPerfData: {},
|
|
163
|
+
});
|
|
137
164
|
}
|
|
138
165
|
}
|
|
139
166
|
afterProcessingOp(message) {
|
|
@@ -158,14 +185,19 @@ class OpPerfTelemetry {
|
|
|
158
185
|
this.sequenceNumberForMsnTracking = undefined;
|
|
159
186
|
}
|
|
160
187
|
if (this.clientId === message.clientId &&
|
|
161
|
-
this.
|
|
162
|
-
|
|
188
|
+
(this.opLatencyLogger.isSamplingDisabled ||
|
|
189
|
+
this.clientSequenceNumberForLatencyStatistics === message.clientSequenceNumber)) {
|
|
190
|
+
// We do an explicit check for undefined right after this
|
|
191
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
192
|
+
const latencyData = this.latencyStatistics.get(message.clientSequenceNumber);
|
|
193
|
+
(0, core_utils_1.assert)(latencyData !== undefined, 0x7c5 /* Undefined latency statistics for op */);
|
|
194
|
+
(0, core_utils_1.assert)(latencyData.opProcessingTimes.submitOpEventTime !== undefined, 0x120 /* "Undefined latency statistics for op (op send time)" */);
|
|
163
195
|
const currentTime = Date.now();
|
|
164
|
-
if (
|
|
165
|
-
|
|
166
|
-
currentTime -
|
|
196
|
+
if (latencyData.opProcessingTimes.inboundPushEventTime !== undefined) {
|
|
197
|
+
latencyData.opPerfData.durationInboundToProcessing =
|
|
198
|
+
currentTime - latencyData.opProcessingTimes.inboundPushEventTime;
|
|
167
199
|
}
|
|
168
|
-
const duration = currentTime -
|
|
200
|
+
const duration = currentTime - latencyData.opProcessingTimes.submitOpEventTime;
|
|
169
201
|
// One of the core expectations for Fluid service is to be fast.
|
|
170
202
|
// When it's not the case, we want to learn about it and be able to investigate, so
|
|
171
203
|
// raise awareness.
|
|
@@ -174,7 +206,7 @@ class OpPerfTelemetry {
|
|
|
174
206
|
// The threshold could be adjusted, but ideally it stays workload-agnostic, as service
|
|
175
207
|
// performance impacts all workloads relying on service.
|
|
176
208
|
const category = duration > exports.latencyThreshold ? "error" : "performance";
|
|
177
|
-
this.
|
|
209
|
+
this.opLatencyLogger.sendPerformanceEvent({
|
|
178
210
|
eventName: "OpRoundtripTime",
|
|
179
211
|
sequenceNumber,
|
|
180
212
|
referenceSequenceNumber: message.referenceSequenceNumber,
|
|
@@ -182,14 +214,15 @@ class OpPerfTelemetry {
|
|
|
182
214
|
category,
|
|
183
215
|
pingLatency: this.pingLatency,
|
|
184
216
|
msnDistance: this.deltaManager.lastSequenceNumber - this.deltaManager.minimumSequenceNumber,
|
|
185
|
-
...
|
|
217
|
+
...latencyData.opPerfData,
|
|
186
218
|
});
|
|
187
219
|
this.clientSequenceNumberForLatencyStatistics = undefined;
|
|
188
|
-
this.
|
|
189
|
-
this.opProcessingTimes = {};
|
|
220
|
+
this.latencyStatistics.delete(message.clientSequenceNumber);
|
|
190
221
|
}
|
|
191
222
|
}
|
|
192
223
|
}
|
|
224
|
+
OpPerfTelemetry.OP_LATENCY_SAMPLE_RATE = 500;
|
|
225
|
+
OpPerfTelemetry.DELTA_LATENCY_SAMPLE_RATE = 100;
|
|
193
226
|
function ReportOpPerfTelemetry(clientId, deltaManager, logger) {
|
|
194
227
|
new OpPerfTelemetry(clientId, deltaManager, logger);
|
|
195
228
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"connectionTelemetry.js","sourceRoot":"","sources":["../src/connectionTelemetry.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAEH,qEAIyC;AAEzC,+EAI8C;AAC9C,2DAAoD;AACpD,+DAA2D;AAE3D;;GAEG;AACU,QAAA,gBAAgB,GAAG,IAAI,CAAC;AAgCrC,MAAM,eAAe;IAuBpB,YACS,QAA4B,EACnB,YAAwE,EACzF,MAA2B;QAFnB,aAAQ,GAAR,QAAQ,CAAoB;QACnB,iBAAY,GAAZ,YAAY,CAA4D;QAxBlF,cAAS,GAAW,CAAC,CAAC;QAKtB,yBAAoB,GAAW,CAAC,CAAC;QAIjC,sBAAiB,GAA4B,EAAE,CAAC;QAExD,sEAAsE;QAC9D,eAAU,GAAwC,EAAE,CAAC;QAErD,oBAAe,GAAG,IAAI,CAAC;QAEd,aAAQ,GAAG,0BAAW,CAAC,GAAG,EAAE,CAAC;QACtC,wBAAmB,GAAG,CAAC,CAAC;QACxB,QAAG,GAAG,CAAC,CAAC;QASf,IAAI,CAAC,MAAM,GAAG,IAAA,mCAAiB,EAAC,EAAE,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,CAAC,CAAC;QAEjE,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;YACtD,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC;YACjC,IAAI,SAAS,KAAK,SAAS,EAAE;gBAC5B,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;oBAClB,IAAI,CAAC,qBAAqB,EAAE,CAAC;iBAC7B;aACD;QACF,CAAC,CAAC,CAAC;QACH,IAAI,CAAC,YAAY,CAAC,EAAE,CAAC,YAAY,EAAE,GAAG,EAAE;YACvC,IAAI,CAAC,4BAA4B,GAAG,SAAS,CAAC;YAC9C,IAAI,CAAC,wCAAwC,GAAG,SAAS,CAAC;YAC1D,IAAI,CAAC,iBAAiB,GAAG,EAAE,CAAC;YAC5B,IAAI,CAAC,UAAU,GAAG,EAAE,CAAC;YACrB,IAAI,CAAC,qBAAqB,GAAG,SAAS,CAAC;YACvC,IAAI,CAAC,eAAe,GAAG,KAAK,CAAC;YAC7B,IAAI,CAAC,SAAS,GAAG,CAAC,CAAC;QACpB,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,EAAE;YAClD,KAAK,MAAM,GAAG,IAAI,QAAQ,EAAE;gBAC3B,IACC,GAAG,CAAC,IAAI,KAAK,kCAAW,CAAC,SAAS;oBAClC,IAAI,CAAC,wCAAwC,KAAK,GAAG,CAAC,oBAAoB,EACzE;oBACD,IAAA,mBAAM,EACL,IAAI,CAAC,iBAAiB,CAAC,qBAAqB,KAAK,SAAS,EAC1D,KAAK,CAAC,iDAAiD,CACvD,CAAC;oBACF,IAAA,mBAAM,EACL,IAAI,CAAC,UAAU,CAAC,eAAe,KAAK,SAAS,EAC7C,KAAK,CAAC,2CAA2C,CACjD,CAAC;oBACF,IAAI,CAAC,iBAAiB,CAAC,qBAAqB,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;oBAE1D,IAAA,mBAAM,EACL,IAAI,CAAC,UAAU,CAAC,wBAAwB,KAAK,SAAS,EACtD,KAAK,CAAC,oDAAoD,CAC1D,CAAC;oBAEF,IAAA,mBAAM,EACL,IAAI,CAAC,iBAAiB,CAAC,iBAAiB,KAAK,SAAS,EACtD,KAAK,CAAC,6CAA6C,CACnD,CAAC;oBAEF,IAAI,CAAC,UAAU,CAAC,wBAAwB;wBACvC,IAAI,CAAC,iBAAiB,CAAC,qBAAqB;4BAC5C,IAAI,CAAC,iBAAiB,CAAC,iBAAiB,CAAC;iBAC1C;aACD;QACF,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,OAAkC,EAAE,EAAE;YAC3E,IACC,IAAI,CAAC,QAAQ,KAAK,OAAO,CAAC,QAAQ;gBAClC,OAAO,CAAC,IAAI,KAAK,kCAAW,CAAC,SAAS;gBACtC,IAAI,CAAC,wCAAwC,KAAK,OAAO,CAAC,oBAAoB;gBAC9E,IAAI,CAAC,iBAAiB,CAAC,qBAAqB,KAAK,SAAS,EACzD;gBACD,IAAI,CAAC,iBAAiB,CAAC,oBAAoB,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;gBACzD,IAAI,CAAC,UAAU,CAAC,eAAe;oBAC9B,IAAI,CAAC,iBAAiB,CAAC,oBAAoB;wBAC3C,IAAI,CAAC,iBAAiB,CAAC,qBAAqB,CAAC;gBAC9C,IAAI,CAAC,iBAAiB,CAAC,qBAAqB,GAAG,SAAS,CAAC;gBACzD,IAAI,CAAC,UAAU,CAAC,kBAAkB,GAAG,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,MAAM,CAAC;aACtE;QACF,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAa,EAAE,QAAgB,EAAE,EAAE;YACxE,oCAAoC;YACpC,gGAAgG;YAChG,0GAA0G;YAC1G,uBAAuB;YACvB,4FAA4F;YAC5F,8BAA8B;YAC9B,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,IAAI,GAAG,EAAE;gBAC9C,IAAI,CAAC,MAAM,CAAC,oBAAoB,CAAC;oBAChC,SAAS,EAAE,wBAAwB;oBACnC,KAAK;oBACL,QAAQ;iBACR,CAAC,CAAC;aACH;QACF,CAAC,CAAC,CAAC;IACJ,CAAC;IAEO,qBAAqB;QAC5B,IAAI,CAAC,qBAAqB,GAAG,SAAS,CAAC;QACvC,IAAI,CAAC,MAAM,CAAC,oBAAoB,CAAC;YAChC,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;gBAClC,CAAC,CAAC,IAAA,4BAAU,EAAC,IAAI,CAAC,mBAAmB,GAAG,IAAI,CAAC,QAAQ,CAAC;gBACtD,CAAC,CAAC,SAAS;YACZ,eAAe,EAAE,IAAI,CAAC,eAAe;SACrC,CAAC,CAAC;IACJ,CAAC;IAEO,cAAc,CAAC,OAAe;QACrC,IAAI,CAAC,WAAW,GAAG,OAAO,CAAC;QAE3B,sCAAsC;QACtC,IAAI,OAAO,GAAG,IAAI,GAAG,EAAE,EAAE;YACxB,IAAI,CAAC,MAAM,CAAC,cAAc,CAAC;gBAC1B,SAAS,EAAE,gBAAgB;gBAC3B,QAAQ,EAAE,OAAO;aACjB,CAAC,CAAC;SACH;QAED,uFAAuF;QACvF,IAAI,IAAI,CAAC,SAAS,GAAG,GAAG,KAAK,CAAC,IAAI,IAAI,CAAC,YAAY,CAAC,MAAM,EAAE;YAC3D,IAAI,CAAC,MAAM,CAAC,oBAAoB,CAAC;gBAChC,SAAS,EAAE,cAAc;gBACzB,QAAQ,EAAE,OAAO;aACjB,CAAC,CAAC;SACH;QACD,IAAI,CAAC,SAAS,EAAE,CAAC;IAClB,CAAC;IAEO,cAAc,CAAC,OAAyB;QAC/C,sEAAsE;QACtE,IACC,IAAI,CAAC,wCAAwC,KAAK,SAAS;YAC3D,OAAO,CAAC,oBAAoB,GAAG,GAAG,KAAK,CAAC,EACvC;YACD,IAAA,mBAAM,EACL,IAAI,CAAC,iBAAiB,CAAC,qBAAqB,KAAK,SAAS,EAC1D,KAAK,CAAC,qDAAqD,CAC3D,CAAC;YACF,IAAA,mBAAM,EACL,IAAI,CAAC,UAAU,CAAC,eAAe,KAAK,SAAS,EAC7C,KAAK,CAAC,2CAA2C,CACjD,CAAC;YACF,IAAI,CAAC,iBAAiB,CAAC,iBAAiB,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;YACtD,IAAI,CAAC,wCAAwC,GAAG,OAAO,CAAC,oBAAoB,CAAC;SAC7E;IACF,CAAC;IAEO,iBAAiB,CAAC,OAAkC;QAC3D,MAAM,cAAc,GAAG,OAAO,CAAC,cAAc,CAAC;QAE9C,IAAI,cAAc,KAAK,IAAI,CAAC,qBAAqB,EAAE;YAClD,IAAI,CAAC,qBAAqB,EAAE,CAAC;SAC7B;QAED,uDAAuD;QACvD,IAAI,IAAI,CAAC,4BAA4B,KAAK,SAAS,IAAI,cAAc,GAAG,IAAI,KAAK,CAAC,EAAE;YACnF,IAAI,CAAC,4BAA4B,GAAG,cAAc,CAAC;YACnD,IAAI,CAAC,oBAAoB,GAAG,OAAO,CAAC,SAAS,CAAC;SAC9C;QACD,IACC,IAAI,CAAC,4BAA4B,KAAK,SAAS;YAC/C,OAAO,CAAC,qBAAqB,IAAI,IAAI,CAAC,4BAA4B,EACjE;YACD,IAAA,mBAAM,EACL,IAAI,CAAC,oBAAoB,KAAK,SAAS,EACvC,KAAK,CAAC,oDAAoD,CAC1D,CAAC;YACF,IAAI,CAAC,MAAM,CAAC,oBAAoB,CAAC;gBAChC,SAAS,EAAE,eAAe;gBAC1B,cAAc;gBACd,WAAW,EAAE,cAAc,GAAG,IAAI,CAAC,4BAA4B;gBAC/D,QAAQ,EAAE,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC,oBAAoB;aACvD,CAAC,CAAC;YACH,IAAI,CAAC,4BAA4B,GAAG,SAAS,CAAC;SAC9C;QAED,IACC,IAAI,CAAC,QAAQ,KAAK,OAAO,CAAC,QAAQ;YAClC,IAAI,CAAC,wCAAwC,KAAK,OAAO,CAAC,oBAAoB,EAC7E;YACD,IAAA,mBAAM,EACL,IAAI,CAAC,iBAAiB,CAAC,iBAAiB,KAAK,SAAS,EACtD,KAAK,CAAC,mDAAmD,CACzD,CAAC;YACF,MAAM,WAAW,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;YAE/B,IAAI,IAAI,CAAC,iBAAiB,CAAC,oBAAoB,KAAK,SAAS,EAAE;gBAC9D,IAAI,CAAC,UAAU,CAAC,2BAA2B;oBAC1C,WAAW,GAAG,IAAI,CAAC,iBAAiB,CAAC,oBAAoB,CAAC;aAC3D;YAED,MAAM,QAAQ,GAAG,WAAW,GAAG,IAAI,CAAC,iBAAiB,CAAC,iBAAiB,CAAC;YAExE,gEAAgE;YAChE,mFAAmF;YACnF,mBAAmB;YACnB,0FAA0F;YAC1F,yFAAyF;YACzF,uFAAuF;YACvF,wDAAwD;YACxD,MAAM,QAAQ,GAAG,QAAQ,GAAG,wBAAgB,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,aAAa,CAAC;YAEvE,IAAI,CAAC,MAAM,CAAC,oBAAoB,CAAC;gBAChC,SAAS,EAAE,iBAAiB;gBAC5B,cAAc;gBACd,uBAAuB,EAAE,OAAO,CAAC,uBAAuB;gBACxD,QAAQ;gBACR,QAAQ;gBACR,WAAW,EAAE,IAAI,CAAC,WAAW;gBAC7B,WAAW,EACV,IAAI,CAAC,YAAY,CAAC,kBAAkB,GAAG,IAAI,CAAC,YAAY,CAAC,qBAAqB;gBAC/E,GAAG,IAAI,CAAC,UAAU;aAClB,CAAC,CAAC;YACH,IAAI,CAAC,wCAAwC,GAAG,SAAS,CAAC;YAC1D,IAAI,CAAC,UAAU,GAAG,EAAE,CAAC;YACrB,IAAI,CAAC,iBAAiB,GAAG,EAAE,CAAC;SAC5B;IACF,CAAC;CACD;AAuBD,SAAgB,qBAAqB,CACpC,QAA4B,EAC5B,YAAwE,EACxE,MAA2B;IAE3B,IAAI,eAAe,CAAC,QAAQ,EAAE,YAAY,EAAE,MAAM,CAAC,CAAC;AACrD,CAAC;AAND,sDAMC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport {\n\tITelemetryLoggerExt,\n\tcreateChildLogger,\n\tformatTick,\n} from \"@fluidframework/telemetry-utils\";\nimport { IDeltaManager } from \"@fluidframework/container-definitions\";\nimport {\n\tIDocumentMessage,\n\tISequencedDocumentMessage,\n\tMessageType,\n} from \"@fluidframework/protocol-definitions\";\nimport { assert } from \"@fluidframework/core-utils\";\nimport { performance } from \"@fluid-internal/client-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\n// Phases in OpPerfTelemetry:\n// 1.\tOp is added to DeltaManager (DM) buffer.\n// 2.\tOp is sent to service (op leaves outbound queue).\n// \t - Note: We do not know for sure when op is sent, we only track when it is added to outbound queue.\n// If outbound queue is paused, time queue is paused is counted as network time.\n// 3.\tOp received from service back (pushed to inbound queue).\n// 4.\tOp is processed.\ninterface IOpPerfTelemetryProperties {\n\t/** Measure time between (1) and (2) - Measure time outbound op is sitting in queue due to active batch */\n\tdurationOutboundBatching: number; // was durationOutboundQueue in previous versions\n\t/** Measure time between (2) and (3) - Track how long it took for op to be acked by service */\n\tdurationNetwork: number; // was durationInboundQueue\n\t/** Measure time between (3) and (4) - Time between DM's inbound \"push\" event until DM's \"op\" event */\n\tdurationInboundToProcessing: number;\n\t/** Length of the DeltaManager's inbound queue at the time of the DM's inbound \"push\" event (3) */\n\tlengthInboundQueue: number;\n}\n\n/**\n * Timings collected at various moments during the op processing.\n */\ninterface IOpPerfTimings {\n\t/** Starting time for (1) */\n\tsubmitOpEventTime: number;\n\t/** Starting time for (2) */\n\toutboundPushEventTime: number;\n\t/** Starting time for (3) */\n\tinboundPushEventTime: number;\n}\n\nclass OpPerfTelemetry {\n\tprivate pongCount: number = 0;\n\tprivate pingLatency: number | undefined;\n\n\t// Collab window tracking. This is timestamp of %1000 message.\n\tprivate sequenceNumberForMsnTracking: number | undefined;\n\tprivate msnTrackingTimestamp: number = 0;\n\t// To track round trip time for every %500 client message.\n\tprivate clientSequenceNumberForLatencyStatistics: number | undefined;\n\n\tprivate opProcessingTimes: Partial<IOpPerfTimings> = {};\n\n\t// Performance Data to be reported for ops round trips and processing.\n\tprivate opPerfData: Partial<IOpPerfTelemetryProperties> = {};\n\n\tprivate firstConnection = true;\n\tprivate connectionOpSeqNumber: number | undefined;\n\tprivate readonly bootTime = performance.now();\n\tprivate connectionStartTime = 0;\n\tprivate gap = 0;\n\n\tprivate readonly logger: ITelemetryLoggerExt;\n\n\tpublic constructor(\n\t\tprivate clientId: string | undefined,\n\t\tprivate readonly deltaManager: IDeltaManager<ISequencedDocumentMessage, IDocumentMessage>,\n\t\tlogger: ITelemetryLoggerExt,\n\t) {\n\t\tthis.logger = createChildLogger({ logger, namespace: \"OpPerf\" });\n\n\t\tthis.deltaManager.on(\"pong\", (latency) => this.recordPingTime(latency));\n\t\tthis.deltaManager.on(\"submitOp\", (message) => this.beforeOpSubmit(message));\n\n\t\tthis.deltaManager.on(\"op\", (message) => this.afterProcessingOp(message));\n\n\t\tthis.deltaManager.on(\"connect\", (details, opsBehind) => {\n\t\t\tthis.clientId = details.clientId;\n\t\t\tif (opsBehind !== undefined) {\n\t\t\t\tthis.connectionOpSeqNumber = this.deltaManager.lastKnownSeqNumber;\n\t\t\t\tthis.gap = opsBehind;\n\t\t\t\tthis.connectionStartTime = performance.now();\n\n\t\t\t\t// We might be already up-today. If so, report it right away.\n\t\t\t\tif (this.gap <= 0) {\n\t\t\t\t\tthis.reportGettingUpToDate();\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t\tthis.deltaManager.on(\"disconnect\", () => {\n\t\t\tthis.sequenceNumberForMsnTracking = undefined;\n\t\t\tthis.clientSequenceNumberForLatencyStatistics = undefined;\n\t\t\tthis.opProcessingTimes = {};\n\t\t\tthis.opPerfData = {};\n\t\t\tthis.connectionOpSeqNumber = undefined;\n\t\t\tthis.firstConnection = false;\n\t\t\tthis.pongCount = 0;\n\t\t});\n\n\t\tthis.deltaManager.outbound.on(\"push\", (messages) => {\n\t\t\tfor (const msg of messages) {\n\t\t\t\tif (\n\t\t\t\t\tmsg.type === MessageType.Operation &&\n\t\t\t\t\tthis.clientSequenceNumberForLatencyStatistics === msg.clientSequenceNumber\n\t\t\t\t) {\n\t\t\t\t\tassert(\n\t\t\t\t\t\tthis.opProcessingTimes.outboundPushEventTime === undefined,\n\t\t\t\t\t\t0x2c8 /* \"outboundPushEventTime should be undefined\" */,\n\t\t\t\t\t);\n\t\t\t\t\tassert(\n\t\t\t\t\t\tthis.opPerfData.durationNetwork === undefined,\n\t\t\t\t\t\t0x2c9 /* \"durationNetwork should be undefined\" */,\n\t\t\t\t\t);\n\t\t\t\t\tthis.opProcessingTimes.outboundPushEventTime = Date.now();\n\n\t\t\t\t\tassert(\n\t\t\t\t\t\tthis.opPerfData.durationOutboundBatching === undefined,\n\t\t\t\t\t\t0x2ca /* \"durationOutboundBatching should be undefined\" */,\n\t\t\t\t\t);\n\n\t\t\t\t\tassert(\n\t\t\t\t\t\tthis.opProcessingTimes.submitOpEventTime !== undefined,\n\t\t\t\t\t\t0x2cb /* \"submitOpEventTime should be undefined\" */,\n\t\t\t\t\t);\n\n\t\t\t\t\tthis.opPerfData.durationOutboundBatching =\n\t\t\t\t\t\tthis.opProcessingTimes.outboundPushEventTime -\n\t\t\t\t\t\tthis.opProcessingTimes.submitOpEventTime;\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\n\t\tthis.deltaManager.inbound.on(\"push\", (message: ISequencedDocumentMessage) => {\n\t\t\tif (\n\t\t\t\tthis.clientId === message.clientId &&\n\t\t\t\tmessage.type === MessageType.Operation &&\n\t\t\t\tthis.clientSequenceNumberForLatencyStatistics === message.clientSequenceNumber &&\n\t\t\t\tthis.opProcessingTimes.outboundPushEventTime !== undefined\n\t\t\t) {\n\t\t\t\tthis.opProcessingTimes.inboundPushEventTime = Date.now();\n\t\t\t\tthis.opPerfData.durationNetwork =\n\t\t\t\t\tthis.opProcessingTimes.inboundPushEventTime -\n\t\t\t\t\tthis.opProcessingTimes.outboundPushEventTime;\n\t\t\t\tthis.opProcessingTimes.outboundPushEventTime = undefined;\n\t\t\t\tthis.opPerfData.lengthInboundQueue = this.deltaManager.inbound.length;\n\t\t\t}\n\t\t});\n\n\t\tthis.deltaManager.inbound.on(\"idle\", (count: number, duration: number) => {\n\t\t\t// Do not want to log zero for sure.\n\t\t\t// We are more interested in aggregates, so logging only if we are processing some number of ops\n\t\t\t// Cut-off is arbitrary - can be increased or decreased based on amount of data collected and questions we\n\t\t\t// want to get answered\n\t\t\t// back-compat: Once 0.36 loader version saturates (count & duration args were added there),\n\t\t\t// we can remove typeof check.\n\t\t\tif (typeof count === \"number\" && count >= 100) {\n\t\t\t\tthis.logger.sendPerformanceEvent({\n\t\t\t\t\teventName: \"GetDeltas_OpProcessing\",\n\t\t\t\t\tcount,\n\t\t\t\t\tduration,\n\t\t\t\t});\n\t\t\t}\n\t\t});\n\t}\n\n\tprivate reportGettingUpToDate() {\n\t\tthis.connectionOpSeqNumber = undefined;\n\t\tthis.logger.sendPerformanceEvent({\n\t\t\teventName: \"ConnectionSpeed\",\n\t\t\tduration: performance.now() - this.connectionStartTime,\n\t\t\tops: this.gap,\n\t\t\t// track time to connect only for first connection.\n\t\t\ttimeToConnect: this.firstConnection\n\t\t\t\t? formatTick(this.connectionStartTime - this.bootTime)\n\t\t\t\t: undefined,\n\t\t\tfirstConnection: this.firstConnection,\n\t\t});\n\t}\n\n\tprivate recordPingTime(latency: number) {\n\t\tthis.pingLatency = latency;\n\n\t\t// Log if latency is longer than 1 min\n\t\tif (latency > 1000 * 60) {\n\t\t\tthis.logger.sendErrorEvent({\n\t\t\t\teventName: \"LatencyTooLong\",\n\t\t\t\tduration: latency,\n\t\t\t});\n\t\t}\n\n\t\t// logging one in every 100 pongs, including the first time, if it is a \"write\" client.\n\t\tif (this.pongCount % 100 === 0 && this.deltaManager.active) {\n\t\t\tthis.logger.sendPerformanceEvent({\n\t\t\t\teventName: \"DeltaLatency\",\n\t\t\t\tduration: latency,\n\t\t\t});\n\t\t}\n\t\tthis.pongCount++;\n\t}\n\n\tprivate beforeOpSubmit(message: IDocumentMessage) {\n\t\t// start with first client op and measure latency every 500 client ops\n\t\tif (\n\t\t\tthis.clientSequenceNumberForLatencyStatistics === undefined &&\n\t\t\tmessage.clientSequenceNumber % 500 === 1\n\t\t) {\n\t\t\tassert(\n\t\t\t\tthis.opProcessingTimes.outboundPushEventTime === undefined,\n\t\t\t\t0x2cc /* \"OpTimeSittingInboundQueue should be undefined\" */,\n\t\t\t);\n\t\t\tassert(\n\t\t\t\tthis.opPerfData.durationNetwork === undefined,\n\t\t\t\t0x2cd /* \"durationNetwork should be undefined\" */,\n\t\t\t);\n\t\t\tthis.opProcessingTimes.submitOpEventTime = Date.now();\n\t\t\tthis.clientSequenceNumberForLatencyStatistics = message.clientSequenceNumber;\n\t\t}\n\t}\n\n\tprivate afterProcessingOp(message: ISequencedDocumentMessage) {\n\t\tconst sequenceNumber = message.sequenceNumber;\n\n\t\tif (sequenceNumber === this.connectionOpSeqNumber) {\n\t\t\tthis.reportGettingUpToDate();\n\t\t}\n\n\t\t// Record collab window max size after every 1000th op.\n\t\tif (this.sequenceNumberForMsnTracking === undefined && sequenceNumber % 1000 === 0) {\n\t\t\tthis.sequenceNumberForMsnTracking = sequenceNumber;\n\t\t\tthis.msnTrackingTimestamp = message.timestamp;\n\t\t}\n\t\tif (\n\t\t\tthis.sequenceNumberForMsnTracking !== undefined &&\n\t\t\tmessage.minimumSequenceNumber >= this.sequenceNumberForMsnTracking\n\t\t) {\n\t\t\tassert(\n\t\t\t\tthis.msnTrackingTimestamp !== undefined,\n\t\t\t\t0x2ce /* \"msnTrackingTimestamp should not be undefined\" */,\n\t\t\t);\n\t\t\tthis.logger.sendPerformanceEvent({\n\t\t\t\teventName: \"MsnStatistics\",\n\t\t\t\tsequenceNumber,\n\t\t\t\tmsnDistance: sequenceNumber - this.sequenceNumberForMsnTracking,\n\t\t\t\tduration: message.timestamp - this.msnTrackingTimestamp,\n\t\t\t});\n\t\t\tthis.sequenceNumberForMsnTracking = undefined;\n\t\t}\n\n\t\tif (\n\t\t\tthis.clientId === message.clientId &&\n\t\t\tthis.clientSequenceNumberForLatencyStatistics === message.clientSequenceNumber\n\t\t) {\n\t\t\tassert(\n\t\t\t\tthis.opProcessingTimes.submitOpEventTime !== undefined,\n\t\t\t\t0x120 /* \"Undefined latency statistics (op send time)\" */,\n\t\t\t);\n\t\t\tconst currentTime = Date.now();\n\n\t\t\tif (this.opProcessingTimes.inboundPushEventTime !== undefined) {\n\t\t\t\tthis.opPerfData.durationInboundToProcessing =\n\t\t\t\t\tcurrentTime - this.opProcessingTimes.inboundPushEventTime;\n\t\t\t}\n\n\t\t\tconst duration = currentTime - this.opProcessingTimes.submitOpEventTime;\n\n\t\t\t// One of the core expectations for Fluid service is to be fast.\n\t\t\t// When it's not the case, we want to learn about it and be able to investigate, so\n\t\t\t// raise awareness.\n\t\t\t// This also helps identify cases where it's due to client behavior (sending too many ops)\n\t\t\t// that results in overwhelming ordering service and thus starting to see long latencies.\n\t\t\t// The threshold could be adjusted, but ideally it stays workload-agnostic, as service\n\t\t\t// performance impacts all workloads relying on service.\n\t\t\tconst category = duration > latencyThreshold ? \"error\" : \"performance\";\n\n\t\t\tthis.logger.sendPerformanceEvent({\n\t\t\t\teventName: \"OpRoundtripTime\",\n\t\t\t\tsequenceNumber,\n\t\t\t\treferenceSequenceNumber: message.referenceSequenceNumber,\n\t\t\t\tduration,\n\t\t\t\tcategory,\n\t\t\t\tpingLatency: this.pingLatency,\n\t\t\t\tmsnDistance:\n\t\t\t\t\tthis.deltaManager.lastSequenceNumber - this.deltaManager.minimumSequenceNumber,\n\t\t\t\t...this.opPerfData,\n\t\t\t});\n\t\t\tthis.clientSequenceNumberForLatencyStatistics = undefined;\n\t\t\tthis.opPerfData = {};\n\t\t\tthis.opProcessingTimes = {};\n\t\t}\n\t}\n}\nexport interface IPerfSignalReport {\n\t/**\n\t * Identifier for the signal being submitted in order to\n\t * allow collection of data around the roundtrip of signal messages.\n\t */\n\tsignalSequenceNumber: number;\n\t/**\n\t * Number of signals that were expected but not received.\n\t */\n\tsignalsLost: number;\n\n\t/**\n\t * Timestamp before submitting the signal we will trace.\n\t */\n\tsignalTimestamp: number;\n\n\t/**\n\t * Expected Signal Sequence to be received.\n\t */\n\ttrackingSignalSequenceNumber: number | undefined;\n}\n\nexport function ReportOpPerfTelemetry(\n\tclientId: string | undefined,\n\tdeltaManager: IDeltaManager<ISequencedDocumentMessage, IDocumentMessage>,\n\tlogger: ITelemetryLoggerExt,\n) {\n\tnew OpPerfTelemetry(clientId, deltaManager, logger);\n}\n"]}
|
|
1
|
+
{"version":3,"file":"connectionTelemetry.js","sourceRoot":"","sources":["../src/connectionTelemetry.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAEH,qEAOyC;AAEzC,+EAI8C;AAC9C,2DAAoD;AACpD,+DAA2D;AAE3D;;GAEG;AACU,QAAA,gBAAgB,GAAG,IAAI,CAAC;AAgCrC,MAAM,eAAe;IA+BpB,YACS,QAA4B,EACnB,YAAwE,EACzF,MAA2B;QAFnB,aAAQ,GAAR,QAAQ,CAAoB;QACnB,iBAAY,GAAZ,YAAY,CAA4D;QA5BlF,yBAAoB,GAAW,CAAC,CAAC;QAGzC,sEAAsE;QACrD,sBAAiB,GAAG,IAAI,GAAG,EAMzC,CAAC;QAEI,oBAAe,GAAG,IAAI,CAAC;QAEd,aAAQ,GAAG,0BAAW,CAAC,GAAG,EAAE,CAAC;QACtC,wBAAmB,GAAG,CAAC,CAAC;QACxB,QAAG,GAAG,CAAC,CAAC;QAef,IAAI,CAAC,MAAM,GAAG,IAAA,mCAAiB,EAAC,EAAE,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,CAAC,CAAC;QAEjE,MAAM,wBAAwB,GAAkB,CAAC,GAAG,EAAE;YACrD,IAAI,UAAU,GAAG,CAAC,CAAC,CAAC;YACpB,OAAO;gBACN,MAAM,EAAE,GAAG,EAAE;oBACZ,UAAU,EAAE,CAAC;oBACb,MAAM,YAAY,GACjB,UAAU,GAAG,eAAe,CAAC,yBAAyB,KAAK,CAAC,CAAC;oBAC9D,IAAI,YAAY,EAAE;wBACjB,UAAU,GAAG,CAAC,CAAC;qBACf;oBACD,OAAO,YAAY,CAAC;gBACrB,CAAC;aACD,CAAC;QACH,CAAC,CAAC,EAAE,CAAC;QAEL,IAAI,CAAC,kBAAkB,GAAG,IAAA,qCAAmB,EAAC,MAAM,EAAE,wBAAwB,CAAC,CAAC;QAEhF,4FAA4F;QAC5F,4GAA4G;QAC5G,wFAAwF;QACxF,IAAI,CAAC,eAAe,GAAG,IAAA,qCAAmB,EAAC,MAAM,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;YACtD,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC;YACjC,IAAI,SAAS,KAAK,SAAS,EAAE;gBAC5B,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;oBAClB,IAAI,CAAC,qBAAqB,EAAE,CAAC;iBAC7B;aACD;QACF,CAAC,CAAC,CAAC;QACH,IAAI,CAAC,YAAY,CAAC,EAAE,CAAC,YAAY,EAAE,GAAG,EAAE;YACvC,IAAI,CAAC,4BAA4B,GAAG,SAAS,CAAC;YAC9C,IAAI,CAAC,wCAAwC,GAAG,SAAS,CAAC;YAC1D,IAAI,CAAC,qBAAqB,GAAG,SAAS,CAAC;YACvC,IAAI,CAAC,eAAe,GAAG,KAAK,CAAC;YAC7B,IAAI,CAAC,iBAAiB,CAAC,KAAK,EAAE,CAAC;QAChC,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,EAAE;YAClD,KAAK,MAAM,GAAG,IAAI,QAAQ,EAAE;gBAC3B,IACC,GAAG,CAAC,IAAI,KAAK,kCAAW,CAAC,SAAS;oBAClC,CAAC,IAAI,CAAC,eAAe,CAAC,kBAAkB;wBACvC,IAAI,CAAC,wCAAwC,KAAK,GAAG,CAAC,oBAAoB,CAAC,EAC3E;oBACD,oEAAoE;oBACpE,MAAM,YAAY,GAAG,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,GAAG,CAAC,oBAAoB,CAAE,CAAC;oBAC3E,IAAA,mBAAM,EACL,YAAY,KAAK,SAAS,EAC1B,KAAK,CAAC,uCAAuC,CAC7C,CAAC;oBACF,IAAA,mBAAM,EACL,YAAY,CAAC,iBAAiB,CAAC,qBAAqB,KAAK,SAAS,EAClE,KAAK,CAAC,iDAAiD,CACvD,CAAC;oBACF,IAAA,mBAAM,EACL,YAAY,CAAC,UAAU,CAAC,eAAe,KAAK,SAAS,EACrD,KAAK,CAAC,2CAA2C,CACjD,CAAC;oBACF,YAAY,CAAC,iBAAiB,CAAC,qBAAqB,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;oBAElE,IAAA,mBAAM,EACL,YAAY,CAAC,UAAU,CAAC,wBAAwB,KAAK,SAAS,EAC9D,KAAK,CAAC,oDAAoD,CAC1D,CAAC;oBAEF,IAAA,mBAAM,EACL,YAAY,CAAC,iBAAiB,CAAC,iBAAiB,KAAK,SAAS,EAC9D,KAAK,CAAC,6CAA6C,CACnD,CAAC;oBAEF,YAAY,CAAC,UAAU,CAAC,wBAAwB;wBAC/C,YAAY,CAAC,iBAAiB,CAAC,qBAAqB;4BACpD,YAAY,CAAC,iBAAiB,CAAC,iBAAiB,CAAC;iBAClD;aACD;QACF,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,OAAkC,EAAE,EAAE;YAC3E,IACC,IAAI,CAAC,QAAQ,KAAK,OAAO,CAAC,QAAQ;gBAClC,OAAO,CAAC,IAAI,KAAK,kCAAW,CAAC,SAAS;gBACtC,CAAC,IAAI,CAAC,eAAe,CAAC,kBAAkB;oBACvC,IAAI,CAAC,wCAAwC,KAAK,OAAO,CAAC,oBAAoB,CAAC,EAC/E;gBACD,yDAAyD;gBACzD,oEAAoE;gBACpE,MAAM,YAAY,GAAG,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,OAAO,CAAC,oBAAoB,CAAE,CAAC;gBAC/E,IAAA,mBAAM,EAAC,YAAY,KAAK,SAAS,EAAE,KAAK,CAAC,uCAAuC,CAAC,CAAC;gBAClF,IAAI,YAAY,CAAC,iBAAiB,CAAC,qBAAqB,KAAK,SAAS,EAAE;oBACvE,YAAY,CAAC,iBAAiB,CAAC,oBAAoB,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;oBACjE,YAAY,CAAC,UAAU,CAAC,eAAe;wBACtC,YAAY,CAAC,iBAAiB,CAAC,oBAAoB;4BACnD,YAAY,CAAC,iBAAiB,CAAC,qBAAqB,CAAC;oBACtD,YAAY,CAAC,UAAU,CAAC,kBAAkB,GAAG,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,MAAM,CAAC;iBAC9E;aACD;QACF,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAa,EAAE,QAAgB,EAAE,EAAE;YACxE,oCAAoC;YACpC,gGAAgG;YAChG,0GAA0G;YAC1G,uBAAuB;YACvB,4FAA4F;YAC5F,8BAA8B;YAC9B,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,IAAI,GAAG,EAAE;gBAC9C,IAAI,CAAC,MAAM,CAAC,oBAAoB,CAAC;oBAChC,SAAS,EAAE,wBAAwB;oBACnC,KAAK;oBACL,QAAQ;iBACR,CAAC,CAAC;aACH;QACF,CAAC,CAAC,CAAC;IACJ,CAAC;IAEO,qBAAqB;QAC5B,IAAI,CAAC,qBAAqB,GAAG,SAAS,CAAC;QACvC,IAAI,CAAC,MAAM,CAAC,oBAAoB,CAAC;YAChC,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;gBAClC,CAAC,CAAC,IAAA,4BAAU,EAAC,IAAI,CAAC,mBAAmB,GAAG,IAAI,CAAC,QAAQ,CAAC;gBACtD,CAAC,CAAC,SAAS;YACZ,eAAe,EAAE,IAAI,CAAC,eAAe;SACrC,CAAC,CAAC;IACJ,CAAC;IAEO,cAAc,CAAC,OAAe;QACrC,IAAI,CAAC,WAAW,GAAG,OAAO,CAAC;QAE3B,sCAAsC;QACtC,IAAI,OAAO,GAAG,IAAI,GAAG,EAAE,EAAE;YACxB,IAAI,CAAC,MAAM,CAAC,cAAc,CAAC;gBAC1B,SAAS,EAAE,gBAAgB;gBAC3B,QAAQ,EAAE,OAAO;aACjB,CAAC,CAAC;SACH;QAED,6GAA6G;QAC7G,IAAI,IAAI,CAAC,YAAY,CAAC,MAAM,EAAE;YAC7B,IAAI,CAAC,kBAAkB,CAAC,oBAAoB,CAAC;gBAC5C,SAAS,EAAE,cAAc;gBACzB,QAAQ,EAAE,OAAO;aACjB,CAAC,CAAC;SACH;IACF,CAAC;IAEO,cAAc,CAAC,OAAyB;QAC/C,sEAAsE;QACtE,IACC,IAAI,CAAC,eAAe,CAAC,kBAAkB;YACvC,CAAC,IAAI,CAAC,wCAAwC,KAAK,SAAS;gBAC3D,OAAO,CAAC,oBAAoB,GAAG,eAAe,CAAC,sBAAsB,KAAK,CAAC,CAAC,EAC5E;YACD,IAAA,mBAAM,EACL,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,OAAO,CAAC,oBAAoB,CAAC,KAAK,SAAS,EACtE,KAAK,CAAC,sDAAsD,CAC5D,CAAC;YACF,IAAI,CAAC,wCAAwC,GAAG,OAAO,CAAC,oBAAoB,CAAC;YAC7E,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,OAAO,CAAC,oBAAoB,EAAE;gBACxD,iBAAiB,EAAE;oBAClB,iBAAiB,EAAE,IAAI,CAAC,GAAG,EAAE;iBAC7B;gBACD,UAAU,EAAE,EAAE;aACd,CAAC,CAAC;SACH;IACF,CAAC;IAEO,iBAAiB,CAAC,OAAkC;QAC3D,MAAM,cAAc,GAAG,OAAO,CAAC,cAAc,CAAC;QAE9C,IAAI,cAAc,KAAK,IAAI,CAAC,qBAAqB,EAAE;YAClD,IAAI,CAAC,qBAAqB,EAAE,CAAC;SAC7B;QAED,uDAAuD;QACvD,IAAI,IAAI,CAAC,4BAA4B,KAAK,SAAS,IAAI,cAAc,GAAG,IAAI,KAAK,CAAC,EAAE;YACnF,IAAI,CAAC,4BAA4B,GAAG,cAAc,CAAC;YACnD,IAAI,CAAC,oBAAoB,GAAG,OAAO,CAAC,SAAS,CAAC;SAC9C;QACD,IACC,IAAI,CAAC,4BAA4B,KAAK,SAAS;YAC/C,OAAO,CAAC,qBAAqB,IAAI,IAAI,CAAC,4BAA4B,EACjE;YACD,IAAA,mBAAM,EACL,IAAI,CAAC,oBAAoB,KAAK,SAAS,EACvC,KAAK,CAAC,oDAAoD,CAC1D,CAAC;YACF,IAAI,CAAC,MAAM,CAAC,oBAAoB,CAAC;gBAChC,SAAS,EAAE,eAAe;gBAC1B,cAAc;gBACd,WAAW,EAAE,cAAc,GAAG,IAAI,CAAC,4BAA4B;gBAC/D,QAAQ,EAAE,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC,oBAAoB;aACvD,CAAC,CAAC;YACH,IAAI,CAAC,4BAA4B,GAAG,SAAS,CAAC;SAC9C;QAED,IACC,IAAI,CAAC,QAAQ,KAAK,OAAO,CAAC,QAAQ;YAClC,CAAC,IAAI,CAAC,eAAe,CAAC,kBAAkB;gBACvC,IAAI,CAAC,wCAAwC,KAAK,OAAO,CAAC,oBAAoB,CAAC,EAC/E;YACD,yDAAyD;YACzD,oEAAoE;YACpE,MAAM,WAAW,GAAG,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,OAAO,CAAC,oBAAoB,CAAE,CAAC;YAC9E,IAAA,mBAAM,EAAC,WAAW,KAAK,SAAS,EAAE,KAAK,CAAC,yCAAyC,CAAC,CAAC;YACnF,IAAA,mBAAM,EACL,WAAW,CAAC,iBAAiB,CAAC,iBAAiB,KAAK,SAAS,EAC7D,KAAK,CAAC,0DAA0D,CAChE,CAAC;YACF,MAAM,WAAW,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;YAC/B,IAAI,WAAW,CAAC,iBAAiB,CAAC,oBAAoB,KAAK,SAAS,EAAE;gBACrE,WAAW,CAAC,UAAU,CAAC,2BAA2B;oBACjD,WAAW,GAAG,WAAW,CAAC,iBAAiB,CAAC,oBAAoB,CAAC;aAClE;YACD,MAAM,QAAQ,GAAG,WAAW,GAAG,WAAW,CAAC,iBAAiB,CAAC,iBAAiB,CAAC;YAE/E,gEAAgE;YAChE,mFAAmF;YACnF,mBAAmB;YACnB,0FAA0F;YAC1F,yFAAyF;YACzF,uFAAuF;YACvF,wDAAwD;YACxD,MAAM,QAAQ,GAAG,QAAQ,GAAG,wBAAgB,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,aAAa,CAAC;YACvE,IAAI,CAAC,eAAe,CAAC,oBAAoB,CAAC;gBACzC,SAAS,EAAE,iBAAiB;gBAC5B,cAAc;gBACd,uBAAuB,EAAE,OAAO,CAAC,uBAAuB;gBACxD,QAAQ;gBACR,QAAQ;gBACR,WAAW,EAAE,IAAI,CAAC,WAAW;gBAC7B,WAAW,EACV,IAAI,CAAC,YAAY,CAAC,kBAAkB,GAAG,IAAI,CAAC,YAAY,CAAC,qBAAqB;gBAC/E,GAAG,WAAW,CAAC,UAAU;aACzB,CAAC,CAAC;YACH,IAAI,CAAC,wCAAwC,GAAG,SAAS,CAAC;YAC1D,IAAI,CAAC,iBAAiB,CAAC,MAAM,CAAC,OAAO,CAAC,oBAAoB,CAAC,CAAC;SAC5D;IACF,CAAC;;AAzQuB,sCAAsB,GAAG,GAAG,AAAN,CAAO;AAG7B,yCAAyB,GAAG,GAAG,AAAN,CAAO;AA8RzD,SAAgB,qBAAqB,CACpC,QAA4B,EAC5B,YAAwE,EACxE,MAA2B;IAE3B,IAAI,eAAe,CAAC,QAAQ,EAAE,YAAY,EAAE,MAAM,CAAC,CAAC;AACrD,CAAC;AAND,sDAMC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport {\n\tIEventSampler,\n\tISampledTelemetryLogger,\n\tITelemetryLoggerExt,\n\tcreateChildLogger,\n\tcreateSampledLogger,\n\tformatTick,\n} from \"@fluidframework/telemetry-utils\";\nimport { IDeltaManager } from \"@fluidframework/container-definitions\";\nimport {\n\tIDocumentMessage,\n\tISequencedDocumentMessage,\n\tMessageType,\n} from \"@fluidframework/protocol-definitions\";\nimport { assert } from \"@fluidframework/core-utils\";\nimport { performance } from \"@fluid-internal/client-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\n// Phases in OpPerfTelemetry:\n// 1.\tOp is added to DeltaManager (DM) buffer.\n// 2.\tOp is sent to service (op leaves outbound queue).\n// \t - Note: We do not know for sure when op is sent, we only track when it is added to outbound queue.\n// If outbound queue is paused, time queue is paused is counted as network time.\n// 3.\tOp received from service back (pushed to inbound queue).\n// 4.\tOp is processed.\ninterface IOpPerfTelemetryProperties {\n\t/** Measure time between (1) and (2) - Measure time outbound op is sitting in queue due to active batch */\n\tdurationOutboundBatching: number; // was durationOutboundQueue in previous versions\n\t/** Measure time between (2) and (3) - Track how long it took for op to be acked by service */\n\tdurationNetwork: number; // was durationInboundQueue\n\t/** Measure time between (3) and (4) - Time between DM's inbound \"push\" event until DM's \"op\" event */\n\tdurationInboundToProcessing: number;\n\t/** Length of the DeltaManager's inbound queue at the time of the DM's inbound \"push\" event (3) */\n\tlengthInboundQueue: number;\n}\n\n/**\n * Timings collected at various moments during the op processing.\n */\ninterface IOpPerfTimings {\n\t/** Starting time for (1) */\n\tsubmitOpEventTime: number;\n\t/** Starting time for (2) */\n\toutboundPushEventTime: number;\n\t/** Starting time for (3) */\n\tinboundPushEventTime: number;\n}\n\nclass OpPerfTelemetry {\n\tprivate pingLatency: number | undefined;\n\n\t// Collab window tracking. This is timestamp of %1000 message.\n\tprivate sequenceNumberForMsnTracking: number | undefined;\n\tprivate msnTrackingTimestamp: number = 0;\n\t// To track round trip time for every %500 client message.\n\tprivate clientSequenceNumberForLatencyStatistics: number | undefined;\n\t// Performance Data to be reported for ops round trips and processing.\n\tprivate readonly latencyStatistics = new Map<\n\t\tnumber,\n\t\t{\n\t\t\topProcessingTimes: Partial<IOpPerfTimings>;\n\t\t\topPerfData: Partial<IOpPerfTelemetryProperties>;\n\t\t}\n\t>();\n\n\tprivate firstConnection = true;\n\tprivate connectionOpSeqNumber: number | undefined;\n\tprivate readonly bootTime = performance.now();\n\tprivate connectionStartTime = 0;\n\tprivate gap = 0;\n\n\tprivate readonly logger: ITelemetryLoggerExt;\n\n\tprivate static readonly OP_LATENCY_SAMPLE_RATE = 500;\n\tprivate readonly opLatencyLogger: ISampledTelemetryLogger;\n\n\tprivate static readonly DELTA_LATENCY_SAMPLE_RATE = 100;\n\tprivate readonly deltaLatencyLogger: ISampledTelemetryLogger;\n\n\tpublic constructor(\n\t\tprivate clientId: string | undefined,\n\t\tprivate readonly deltaManager: IDeltaManager<ISequencedDocumentMessage, IDocumentMessage>,\n\t\tlogger: ITelemetryLoggerExt,\n\t) {\n\t\tthis.logger = createChildLogger({ logger, namespace: \"OpPerf\" });\n\n\t\tconst deltaLatencyEventSampler: IEventSampler = (() => {\n\t\t\tlet eventCount = -1;\n\t\t\treturn {\n\t\t\t\tsample: () => {\n\t\t\t\t\teventCount++;\n\t\t\t\t\tconst shouldSample =\n\t\t\t\t\t\teventCount % OpPerfTelemetry.DELTA_LATENCY_SAMPLE_RATE === 0;\n\t\t\t\t\tif (shouldSample) {\n\t\t\t\t\t\teventCount = 0;\n\t\t\t\t\t}\n\t\t\t\t\treturn shouldSample;\n\t\t\t\t},\n\t\t\t};\n\t\t})();\n\n\t\tthis.deltaLatencyLogger = createSampledLogger(logger, deltaLatencyEventSampler);\n\n\t\t// The SampledLogger here is used get access to the isSamplingDisabled property dervied from\n\t\t// telemetry config properties. The actual sampling logic for op messages happens outside this SampledLogger\n\t\t// due to complexity of the different asynchronus scenarios of the op message lifecycle.\n\t\tthis.opLatencyLogger = createSampledLogger(logger);\n\n\t\tthis.deltaManager.on(\"pong\", (latency) => this.recordPingTime(latency));\n\t\tthis.deltaManager.on(\"submitOp\", (message) => this.beforeOpSubmit(message));\n\n\t\tthis.deltaManager.on(\"op\", (message) => this.afterProcessingOp(message));\n\n\t\tthis.deltaManager.on(\"connect\", (details, opsBehind) => {\n\t\t\tthis.clientId = details.clientId;\n\t\t\tif (opsBehind !== undefined) {\n\t\t\t\tthis.connectionOpSeqNumber = this.deltaManager.lastKnownSeqNumber;\n\t\t\t\tthis.gap = opsBehind;\n\t\t\t\tthis.connectionStartTime = performance.now();\n\n\t\t\t\t// We might be already up-today. If so, report it right away.\n\t\t\t\tif (this.gap <= 0) {\n\t\t\t\t\tthis.reportGettingUpToDate();\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t\tthis.deltaManager.on(\"disconnect\", () => {\n\t\t\tthis.sequenceNumberForMsnTracking = undefined;\n\t\t\tthis.clientSequenceNumberForLatencyStatistics = undefined;\n\t\t\tthis.connectionOpSeqNumber = undefined;\n\t\t\tthis.firstConnection = false;\n\t\t\tthis.latencyStatistics.clear();\n\t\t});\n\n\t\tthis.deltaManager.outbound.on(\"push\", (messages) => {\n\t\t\tfor (const msg of messages) {\n\t\t\t\tif (\n\t\t\t\t\tmsg.type === MessageType.Operation &&\n\t\t\t\t\t(this.opLatencyLogger.isSamplingDisabled ||\n\t\t\t\t\t\tthis.clientSequenceNumberForLatencyStatistics === msg.clientSequenceNumber)\n\t\t\t\t) {\n\t\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n\t\t\t\t\tconst latencyStats = this.latencyStatistics.get(msg.clientSequenceNumber)!;\n\t\t\t\t\tassert(\n\t\t\t\t\t\tlatencyStats !== undefined,\n\t\t\t\t\t\t0x7c2 /* Latency stats for op should exist */,\n\t\t\t\t\t);\n\t\t\t\t\tassert(\n\t\t\t\t\t\tlatencyStats.opProcessingTimes.outboundPushEventTime === undefined,\n\t\t\t\t\t\t0x2c8 /* \"outboundPushEventTime should be undefined\" */,\n\t\t\t\t\t);\n\t\t\t\t\tassert(\n\t\t\t\t\t\tlatencyStats.opPerfData.durationNetwork === undefined,\n\t\t\t\t\t\t0x2c9 /* \"durationNetwork should be undefined\" */,\n\t\t\t\t\t);\n\t\t\t\t\tlatencyStats.opProcessingTimes.outboundPushEventTime = Date.now();\n\n\t\t\t\t\tassert(\n\t\t\t\t\t\tlatencyStats.opPerfData.durationOutboundBatching === undefined,\n\t\t\t\t\t\t0x2ca /* \"durationOutboundBatching should be undefined\" */,\n\t\t\t\t\t);\n\n\t\t\t\t\tassert(\n\t\t\t\t\t\tlatencyStats.opProcessingTimes.submitOpEventTime !== undefined,\n\t\t\t\t\t\t0x2cb /* \"submitOpEventTime should be undefined\" */,\n\t\t\t\t\t);\n\n\t\t\t\t\tlatencyStats.opPerfData.durationOutboundBatching =\n\t\t\t\t\t\tlatencyStats.opProcessingTimes.outboundPushEventTime -\n\t\t\t\t\t\tlatencyStats.opProcessingTimes.submitOpEventTime;\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\n\t\tthis.deltaManager.inbound.on(\"push\", (message: ISequencedDocumentMessage) => {\n\t\t\tif (\n\t\t\t\tthis.clientId === message.clientId &&\n\t\t\t\tmessage.type === MessageType.Operation &&\n\t\t\t\t(this.opLatencyLogger.isSamplingDisabled ||\n\t\t\t\t\tthis.clientSequenceNumberForLatencyStatistics === message.clientSequenceNumber)\n\t\t\t) {\n\t\t\t\t// We do an explicit check for undefined right after this\n\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n\t\t\t\tconst latencyStats = this.latencyStatistics.get(message.clientSequenceNumber)!;\n\t\t\t\tassert(latencyStats !== undefined, 0x7c3 /* Latency stats for op should exist */);\n\t\t\t\tif (latencyStats.opProcessingTimes.outboundPushEventTime !== undefined) {\n\t\t\t\t\tlatencyStats.opProcessingTimes.inboundPushEventTime = Date.now();\n\t\t\t\t\tlatencyStats.opPerfData.durationNetwork =\n\t\t\t\t\t\tlatencyStats.opProcessingTimes.inboundPushEventTime -\n\t\t\t\t\t\tlatencyStats.opProcessingTimes.outboundPushEventTime;\n\t\t\t\t\tlatencyStats.opPerfData.lengthInboundQueue = this.deltaManager.inbound.length;\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\n\t\tthis.deltaManager.inbound.on(\"idle\", (count: number, duration: number) => {\n\t\t\t// Do not want to log zero for sure.\n\t\t\t// We are more interested in aggregates, so logging only if we are processing some number of ops\n\t\t\t// Cut-off is arbitrary - can be increased or decreased based on amount of data collected and questions we\n\t\t\t// want to get answered\n\t\t\t// back-compat: Once 0.36 loader version saturates (count & duration args were added there),\n\t\t\t// we can remove typeof check.\n\t\t\tif (typeof count === \"number\" && count >= 100) {\n\t\t\t\tthis.logger.sendPerformanceEvent({\n\t\t\t\t\teventName: \"GetDeltas_OpProcessing\",\n\t\t\t\t\tcount,\n\t\t\t\t\tduration,\n\t\t\t\t});\n\t\t\t}\n\t\t});\n\t}\n\n\tprivate reportGettingUpToDate() {\n\t\tthis.connectionOpSeqNumber = undefined;\n\t\tthis.logger.sendPerformanceEvent({\n\t\t\teventName: \"ConnectionSpeed\",\n\t\t\tduration: performance.now() - this.connectionStartTime,\n\t\t\tops: this.gap,\n\t\t\t// track time to connect only for first connection.\n\t\t\ttimeToConnect: this.firstConnection\n\t\t\t\t? formatTick(this.connectionStartTime - this.bootTime)\n\t\t\t\t: undefined,\n\t\t\tfirstConnection: this.firstConnection,\n\t\t});\n\t}\n\n\tprivate recordPingTime(latency: number) {\n\t\tthis.pingLatency = latency;\n\n\t\t// Log if latency is longer than 1 min\n\t\tif (latency > 1000 * 60) {\n\t\t\tthis.logger.sendErrorEvent({\n\t\t\t\teventName: \"LatencyTooLong\",\n\t\t\t\tduration: latency,\n\t\t\t});\n\t\t}\n\n\t\t// logging one in every DELTA_LATENCY_SAMPLE_RATE pongs, including the first time, if it is a \"write\" client.\n\t\tif (this.deltaManager.active) {\n\t\t\tthis.deltaLatencyLogger.sendPerformanceEvent({\n\t\t\t\teventName: \"DeltaLatency\",\n\t\t\t\tduration: latency,\n\t\t\t});\n\t\t}\n\t}\n\n\tprivate beforeOpSubmit(message: IDocumentMessage) {\n\t\t// start with first client op and measure latency every 500 client ops\n\t\tif (\n\t\t\tthis.opLatencyLogger.isSamplingDisabled ||\n\t\t\t(this.clientSequenceNumberForLatencyStatistics === undefined &&\n\t\t\t\tmessage.clientSequenceNumber % OpPerfTelemetry.OP_LATENCY_SAMPLE_RATE === 1)\n\t\t) {\n\t\t\tassert(\n\t\t\t\tthis.latencyStatistics.get(message.clientSequenceNumber) === undefined,\n\t\t\t\t0x7c4 /* Existing op perf data for client sequence number */,\n\t\t\t);\n\t\t\tthis.clientSequenceNumberForLatencyStatistics = message.clientSequenceNumber;\n\t\t\tthis.latencyStatistics.set(message.clientSequenceNumber, {\n\t\t\t\topProcessingTimes: {\n\t\t\t\t\tsubmitOpEventTime: Date.now(),\n\t\t\t\t},\n\t\t\t\topPerfData: {},\n\t\t\t});\n\t\t}\n\t}\n\n\tprivate afterProcessingOp(message: ISequencedDocumentMessage) {\n\t\tconst sequenceNumber = message.sequenceNumber;\n\n\t\tif (sequenceNumber === this.connectionOpSeqNumber) {\n\t\t\tthis.reportGettingUpToDate();\n\t\t}\n\n\t\t// Record collab window max size after every 1000th op.\n\t\tif (this.sequenceNumberForMsnTracking === undefined && sequenceNumber % 1000 === 0) {\n\t\t\tthis.sequenceNumberForMsnTracking = sequenceNumber;\n\t\t\tthis.msnTrackingTimestamp = message.timestamp;\n\t\t}\n\t\tif (\n\t\t\tthis.sequenceNumberForMsnTracking !== undefined &&\n\t\t\tmessage.minimumSequenceNumber >= this.sequenceNumberForMsnTracking\n\t\t) {\n\t\t\tassert(\n\t\t\t\tthis.msnTrackingTimestamp !== undefined,\n\t\t\t\t0x2ce /* \"msnTrackingTimestamp should not be undefined\" */,\n\t\t\t);\n\t\t\tthis.logger.sendPerformanceEvent({\n\t\t\t\teventName: \"MsnStatistics\",\n\t\t\t\tsequenceNumber,\n\t\t\t\tmsnDistance: sequenceNumber - this.sequenceNumberForMsnTracking,\n\t\t\t\tduration: message.timestamp - this.msnTrackingTimestamp,\n\t\t\t});\n\t\t\tthis.sequenceNumberForMsnTracking = undefined;\n\t\t}\n\n\t\tif (\n\t\t\tthis.clientId === message.clientId &&\n\t\t\t(this.opLatencyLogger.isSamplingDisabled ||\n\t\t\t\tthis.clientSequenceNumberForLatencyStatistics === message.clientSequenceNumber)\n\t\t) {\n\t\t\t// We do an explicit check for undefined right after this\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n\t\t\tconst latencyData = this.latencyStatistics.get(message.clientSequenceNumber)!;\n\t\t\tassert(latencyData !== undefined, 0x7c5 /* Undefined latency statistics for op */);\n\t\t\tassert(\n\t\t\t\tlatencyData.opProcessingTimes.submitOpEventTime !== undefined,\n\t\t\t\t0x120 /* \"Undefined latency statistics for op (op send time)\" */,\n\t\t\t);\n\t\t\tconst currentTime = Date.now();\n\t\t\tif (latencyData.opProcessingTimes.inboundPushEventTime !== undefined) {\n\t\t\t\tlatencyData.opPerfData.durationInboundToProcessing =\n\t\t\t\t\tcurrentTime - latencyData.opProcessingTimes.inboundPushEventTime;\n\t\t\t}\n\t\t\tconst duration = currentTime - latencyData.opProcessingTimes.submitOpEventTime;\n\n\t\t\t// One of the core expectations for Fluid service is to be fast.\n\t\t\t// When it's not the case, we want to learn about it and be able to investigate, so\n\t\t\t// raise awareness.\n\t\t\t// This also helps identify cases where it's due to client behavior (sending too many ops)\n\t\t\t// that results in overwhelming ordering service and thus starting to see long latencies.\n\t\t\t// The threshold could be adjusted, but ideally it stays workload-agnostic, as service\n\t\t\t// performance impacts all workloads relying on service.\n\t\t\tconst category = duration > latencyThreshold ? \"error\" : \"performance\";\n\t\t\tthis.opLatencyLogger.sendPerformanceEvent({\n\t\t\t\teventName: \"OpRoundtripTime\",\n\t\t\t\tsequenceNumber,\n\t\t\t\treferenceSequenceNumber: message.referenceSequenceNumber,\n\t\t\t\tduration,\n\t\t\t\tcategory,\n\t\t\t\tpingLatency: this.pingLatency,\n\t\t\t\tmsnDistance:\n\t\t\t\t\tthis.deltaManager.lastSequenceNumber - this.deltaManager.minimumSequenceNumber,\n\t\t\t\t...latencyData.opPerfData,\n\t\t\t});\n\t\t\tthis.clientSequenceNumberForLatencyStatistics = undefined;\n\t\t\tthis.latencyStatistics.delete(message.clientSequenceNumber);\n\t\t}\n\t}\n}\nexport interface IPerfSignalReport {\n\t/**\n\t * Identifier for the signal being submitted in order to\n\t * allow collection of data around the roundtrip of signal messages.\n\t */\n\tsignalSequenceNumber: number;\n\t/**\n\t * Number of signals that were expected but not received.\n\t */\n\tsignalsLost: number;\n\n\t/**\n\t * Timestamp before submitting the signal we will trace.\n\t */\n\tsignalTimestamp: number;\n\n\t/**\n\t * Expected Signal Sequence to be received.\n\t */\n\ttrackingSignalSequenceNumber: number | undefined;\n}\n\nexport function ReportOpPerfTelemetry(\n\tclientId: string | undefined,\n\tdeltaManager: IDeltaManager<ISequencedDocumentMessage, IDocumentMessage>,\n\tlogger: ITelemetryLoggerExt,\n) {\n\tnew OpPerfTelemetry(clientId, deltaManager, logger);\n}\n"]}
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* Licensed under the MIT License.
|
|
4
4
|
*/
|
|
5
5
|
import { FluidObject, IFluidHandle, IFluidHandleContext, IFluidRouter, IRequest, IResponse, IProvideFluidHandleContext } from "@fluidframework/core-interfaces";
|
|
6
|
-
import { IAudience, IContainerContext, IDeltaManager, IRuntime, ICriticalContainerError, AttachState, ILoaderOptions } from "@fluidframework/container-definitions";
|
|
6
|
+
import { IAudience, IContainerContext, IDeltaManager, IRuntime, ICriticalContainerError, AttachState, ILoaderOptions, ILoader, IGetPendingLocalStateProps } from "@fluidframework/container-definitions";
|
|
7
7
|
import { IContainerRuntime, IContainerRuntimeEvents } from "@fluidframework/container-runtime-definitions";
|
|
8
8
|
import { TypedEventEmitter } from "@fluid-internal/client-utils";
|
|
9
9
|
import { ITelemetryLoggerExt } from "@fluidframework/telemetry-utils";
|
|
@@ -12,9 +12,12 @@ import { IClientDetails, IDocumentMessage, IQuorumClients, ISequencedDocumentMes
|
|
|
12
12
|
import { FlushMode, IFluidDataStoreContextDetached, IFluidDataStoreRegistry, IGarbageCollectionData, NamedFluidDataStoreRegistryEntries, ISummaryTreeWithStats, IDataStore, ITelemetryContext, IIdCompressor, IIdCompressorCore } from "@fluidframework/runtime-definitions";
|
|
13
13
|
import { IPendingLocalState } from "./pendingStateManager";
|
|
14
14
|
import { IBlobManagerLoadInfo, IPendingBlobs } from "./blobManager";
|
|
15
|
-
import { IContainerRuntimeMetadata, ISerializedElection, SubmitSummaryResult, ISubmitSummaryOptions, ISummarizerInternalsProvider, ISummarizerRuntime, IRefreshSummaryAckOptions, IOnDemandSummarizeOptions, ISummarizeResults, IEnqueueSummarizeOptions, EnqueueSummarizeResult, ISummarizerEvents } from "./summary";
|
|
15
|
+
import { IContainerRuntimeMetadata, ISerializedElection, SubmitSummaryResult, ISubmitSummaryOptions, ISummarizerInternalsProvider, ISummarizerRuntime, IRefreshSummaryAckOptions, IOnDemandSummarizeOptions, ISummarizeResults, IEnqueueSummarizeOptions, EnqueueSummarizeResult, ISummarizerEvents, ISummarizer } from "./summary";
|
|
16
16
|
import { GCNodeType, IGCRuntimeOptions, IGCStats } from "./gc";
|
|
17
17
|
import { IBatch } from "./opLifecycle";
|
|
18
|
+
/**
|
|
19
|
+
* @public
|
|
20
|
+
*/
|
|
18
21
|
export interface ISummaryBaseConfiguration {
|
|
19
22
|
/**
|
|
20
23
|
* Delay before first attempt to spawn summarizing container.
|
|
@@ -32,6 +35,9 @@ export interface ISummaryBaseConfiguration {
|
|
|
32
35
|
*/
|
|
33
36
|
maxOpsSinceLastSummary: number;
|
|
34
37
|
}
|
|
38
|
+
/**
|
|
39
|
+
* @public
|
|
40
|
+
*/
|
|
35
41
|
export interface ISummaryConfigurationHeuristics extends ISummaryBaseConfiguration {
|
|
36
42
|
state: "enabled";
|
|
37
43
|
/**
|
|
@@ -90,14 +96,29 @@ export interface ISummaryConfigurationHeuristics extends ISummaryBaseConfigurati
|
|
|
90
96
|
*/
|
|
91
97
|
nonRuntimeHeuristicThreshold?: number;
|
|
92
98
|
}
|
|
99
|
+
/**
|
|
100
|
+
* @public
|
|
101
|
+
*/
|
|
93
102
|
export interface ISummaryConfigurationDisableSummarizer {
|
|
94
103
|
state: "disabled";
|
|
95
104
|
}
|
|
105
|
+
/**
|
|
106
|
+
* @public
|
|
107
|
+
*/
|
|
96
108
|
export interface ISummaryConfigurationDisableHeuristics extends ISummaryBaseConfiguration {
|
|
97
109
|
state: "disableHeuristics";
|
|
98
110
|
}
|
|
111
|
+
/**
|
|
112
|
+
* @public
|
|
113
|
+
*/
|
|
99
114
|
export type ISummaryConfiguration = ISummaryConfigurationDisableSummarizer | ISummaryConfigurationDisableHeuristics | ISummaryConfigurationHeuristics;
|
|
115
|
+
/**
|
|
116
|
+
* @public
|
|
117
|
+
*/
|
|
100
118
|
export declare const DefaultSummaryConfiguration: ISummaryConfiguration;
|
|
119
|
+
/**
|
|
120
|
+
* @public
|
|
121
|
+
*/
|
|
101
122
|
export interface ISummaryRuntimeOptions {
|
|
102
123
|
/** Override summary configurations set by the server. */
|
|
103
124
|
summaryConfigOverrides?: ISummaryConfiguration;
|
|
@@ -111,20 +132,23 @@ export interface ISummaryRuntimeOptions {
|
|
|
111
132
|
}
|
|
112
133
|
/**
|
|
113
134
|
* Options for op compression.
|
|
114
|
-
* @
|
|
135
|
+
* @public
|
|
115
136
|
*/
|
|
116
137
|
export interface ICompressionRuntimeOptions {
|
|
117
138
|
/**
|
|
118
|
-
* The
|
|
139
|
+
* The value the batch's content size must exceed for the batch to be compressed.
|
|
140
|
+
* By default the value is 600 * 1024 = 614400 bytes. If the value is set to `Infinity`, compression will be disabled.
|
|
119
141
|
*/
|
|
120
142
|
readonly minimumBatchSizeInBytes: number;
|
|
121
143
|
/**
|
|
122
144
|
* The compression algorithm that will be used to compress the op.
|
|
145
|
+
* By default the value is `lz4` which is the only compression algorithm currently supported.
|
|
123
146
|
*/
|
|
124
147
|
readonly compressionAlgorithm: CompressionAlgorithms;
|
|
125
148
|
}
|
|
126
149
|
/**
|
|
127
150
|
* Options for container runtime.
|
|
151
|
+
* @public
|
|
128
152
|
*/
|
|
129
153
|
export interface IContainerRuntimeOptions {
|
|
130
154
|
readonly summaryOptions?: ISummaryRuntimeOptions;
|
|
@@ -146,8 +170,7 @@ export interface IContainerRuntimeOptions {
|
|
|
146
170
|
*/
|
|
147
171
|
readonly flushMode?: FlushMode;
|
|
148
172
|
/**
|
|
149
|
-
* Enables the runtime to compress ops.
|
|
150
|
-
* @experimental Not ready for use.
|
|
173
|
+
* Enables the runtime to compress ops. See {@link ICompressionRuntimeOptions}.
|
|
151
174
|
*/
|
|
152
175
|
readonly compressionOptions?: ICompressionRuntimeOptions;
|
|
153
176
|
/**
|
|
@@ -164,12 +187,15 @@ export interface IContainerRuntimeOptions {
|
|
|
164
187
|
/**
|
|
165
188
|
* If the op payload needs to be chunked in order to work around the maximum size of the batch, this value represents
|
|
166
189
|
* how large the individual chunks will be. This is only supported when compression is enabled. If after compression, the
|
|
167
|
-
* batch size exceeds this value, it will be chunked into smaller ops of this size.
|
|
190
|
+
* batch content size exceeds this value, it will be chunked into smaller ops of this exact size.
|
|
168
191
|
*
|
|
169
|
-
*
|
|
170
|
-
*
|
|
192
|
+
* This value is a trade-off between having many small chunks vs fewer larger chunks and by default, the runtime is configured to use
|
|
193
|
+
* 200 * 1024 = 204800 bytes. This default value ensures that no compressed payload's content is able to exceed {@link IContainerRuntimeOptions.maxBatchSizeInBytes}
|
|
194
|
+
* regardless of the overhead of an individual op.
|
|
171
195
|
*
|
|
172
|
-
* @
|
|
196
|
+
* Any value of `chunkSizeInBytes` exceeding {@link IContainerRuntimeOptions.maxBatchSizeInBytes} will disable this feature, therefore if a compressed batch's content
|
|
197
|
+
* size exceeds {@link IContainerRuntimeOptions.maxBatchSizeInBytes} after compression, the container will close with an instance of `GenericError` with
|
|
198
|
+
* the `BatchTooLarge` message.
|
|
173
199
|
*/
|
|
174
200
|
readonly chunkSizeInBytes?: number;
|
|
175
201
|
/**
|
|
@@ -201,6 +227,7 @@ export interface IContainerRuntimeOptions {
|
|
|
201
227
|
}
|
|
202
228
|
/**
|
|
203
229
|
* Accepted header keys for requests coming to the runtime.
|
|
230
|
+
* @public
|
|
204
231
|
*/
|
|
205
232
|
export declare enum RuntimeHeaders {
|
|
206
233
|
/** True to wait for a data store to be created and loaded before returning it. */
|
|
@@ -208,13 +235,24 @@ export declare enum RuntimeHeaders {
|
|
|
208
235
|
/** True if the request is coming from an IFluidHandle. */
|
|
209
236
|
viaHandle = "viaHandle"
|
|
210
237
|
}
|
|
211
|
-
/** True if a tombstoned object should be returned without erroring
|
|
238
|
+
/** True if a tombstoned object should be returned without erroring
|
|
239
|
+
* @public
|
|
240
|
+
*/
|
|
212
241
|
export declare const AllowTombstoneRequestHeaderKey = "allowTombstone";
|
|
213
|
-
/**
|
|
242
|
+
/**
|
|
243
|
+
* [IRRELEVANT IF throwOnInactiveLoad OPTION NOT SET] True if an inactive object should be returned without erroring
|
|
244
|
+
* @public
|
|
245
|
+
*/
|
|
214
246
|
export declare const AllowInactiveRequestHeaderKey = "allowInactive";
|
|
215
|
-
/**
|
|
247
|
+
/**
|
|
248
|
+
* Tombstone error responses will have this header set to true
|
|
249
|
+
* @public
|
|
250
|
+
*/
|
|
216
251
|
export declare const TombstoneResponseHeaderKey = "isTombstoned";
|
|
217
|
-
/**
|
|
252
|
+
/**
|
|
253
|
+
* Inactive error responses will have this header set to true
|
|
254
|
+
* @public
|
|
255
|
+
*/
|
|
218
256
|
export declare const InactiveResponseHeaderKey = "isInactive";
|
|
219
257
|
/**
|
|
220
258
|
* The full set of parsed header data that may be found on Runtime requests
|
|
@@ -228,6 +266,7 @@ export interface RuntimeHeaderData {
|
|
|
228
266
|
export declare const defaultRuntimeHeaderData: Required<RuntimeHeaderData>;
|
|
229
267
|
/**
|
|
230
268
|
* Available compression algorithms for op compression.
|
|
269
|
+
* @public
|
|
231
270
|
*/
|
|
232
271
|
export declare enum CompressionAlgorithms {
|
|
233
272
|
lz4 = "lz4"
|
|
@@ -252,7 +291,8 @@ export declare const defaultPendingOpsWaitTimeoutMs = 1000;
|
|
|
252
291
|
/** The default time to delay a summarization retry attempt when there are pending ops */
|
|
253
292
|
export declare const defaultPendingOpsRetryDelayMs = 1000;
|
|
254
293
|
/**
|
|
255
|
-
* @deprecated
|
|
294
|
+
* @deprecated use ContainerRuntimeMessageType instead
|
|
295
|
+
* @public
|
|
256
296
|
*/
|
|
257
297
|
export declare enum RuntimeMessage {
|
|
258
298
|
FluidDataStoreOp = "component",
|
|
@@ -264,13 +304,15 @@ export declare enum RuntimeMessage {
|
|
|
264
304
|
Operation = "op"
|
|
265
305
|
}
|
|
266
306
|
/**
|
|
267
|
-
* @deprecated
|
|
307
|
+
* @deprecated please use version in driver-utils
|
|
308
|
+
* @public
|
|
268
309
|
*/
|
|
269
310
|
export declare function isRuntimeMessage(message: ISequencedDocumentMessage): boolean;
|
|
270
311
|
/**
|
|
271
312
|
* Legacy ID for the built-in AgentScheduler. To minimize disruption while removing it, retaining this as a
|
|
272
313
|
* special-case for document dirty state. Ultimately we should have no special-cases from the
|
|
273
314
|
* ContainerRuntime's perspective.
|
|
315
|
+
* @public
|
|
274
316
|
*/
|
|
275
317
|
export declare const agentSchedulerId = "_scheduler";
|
|
276
318
|
export declare function getDeviceSpec(): {
|
|
@@ -286,9 +328,15 @@ export declare function getDeviceSpec(): {
|
|
|
286
328
|
* we can provide a partially-applied function to keep those items private to the ContainerRuntime.
|
|
287
329
|
*/
|
|
288
330
|
export declare const makeLegacySendBatchFn: (submitFn: (type: MessageType, contents: any, batch: boolean, appData?: any) => number, deltaManager: Pick<IDeltaManager<unknown, unknown>, "flush">) => (batch: IBatch) => void;
|
|
331
|
+
/**
|
|
332
|
+
* This function is not supported publicly and exists for e2e testing
|
|
333
|
+
* @internal
|
|
334
|
+
*/
|
|
335
|
+
export declare function TEST_requestSummarizer(loader: ILoader, url: string): Promise<ISummarizer>;
|
|
289
336
|
/**
|
|
290
337
|
* Represents the runtime of the container. Contains helper functions/state of the container.
|
|
291
338
|
* It will define the store level mappings.
|
|
339
|
+
* @public
|
|
292
340
|
*/
|
|
293
341
|
export declare class ContainerRuntime extends TypedEventEmitter<IContainerRuntimeEvents & ISummarizerEvents> implements IContainerRuntime, IRuntime, ISummarizerRuntime, ISummarizerInternalsProvider, IProvideFluidHandleContext {
|
|
294
342
|
private readonly registry;
|
|
@@ -299,11 +347,11 @@ export declare class ContainerRuntime extends TypedEventEmitter<IContainerRuntim
|
|
|
299
347
|
private readonly requestHandler?;
|
|
300
348
|
private readonly summaryConfiguration;
|
|
301
349
|
/**
|
|
302
|
-
* @deprecated
|
|
350
|
+
* @deprecated Will be removed in future major release. Migrate all usage of IFluidRouter to the "entryPoint" pattern. Refer to Removing-IFluidRouter.md
|
|
303
351
|
*/
|
|
304
352
|
get IFluidRouter(): this;
|
|
305
353
|
/**
|
|
306
|
-
* @deprecated
|
|
354
|
+
* @deprecated use loadRuntime instead.
|
|
307
355
|
* Load the stores from a snapshot and returns the runtime.
|
|
308
356
|
* @param context - Context of the container.
|
|
309
357
|
* @param registryEntries - Mapping to the stores.
|
|
@@ -461,10 +509,12 @@ export declare class ContainerRuntime extends TypedEventEmitter<IContainerRuntim
|
|
|
461
509
|
* a summary is generated.
|
|
462
510
|
*/
|
|
463
511
|
private nextSummaryNumber;
|
|
464
|
-
/**
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
512
|
+
/** If false, loading or using a Tombstoned object should merely log, not fail */
|
|
513
|
+
get gcTombstoneEnforcementAllowed(): boolean;
|
|
514
|
+
/** If true, throw an error when a tombstone data store is retrieved */
|
|
515
|
+
get gcThrowOnTombstoneLoad(): boolean;
|
|
516
|
+
/** If true, throw an error when a tombstone data store is used. */
|
|
517
|
+
get gcThrowOnTombstoneUsage(): boolean;
|
|
468
518
|
/**
|
|
469
519
|
* GUID to identify a document in telemetry
|
|
470
520
|
* ! Note: should not be used for anything other than telemetry and is not considered a stable GUID
|
|
@@ -494,7 +544,7 @@ export declare class ContainerRuntime extends TypedEventEmitter<IContainerRuntim
|
|
|
494
544
|
/**
|
|
495
545
|
* Notifies this object about the request made to the container.
|
|
496
546
|
* @param request - Request made to the handler.
|
|
497
|
-
* @deprecated
|
|
547
|
+
* @deprecated Will be removed in future major release. Migrate all usage of IFluidRouter to the "entryPoint" pattern. Refer to Removing-IFluidRouter.md
|
|
498
548
|
*/
|
|
499
549
|
request(request: IRequest): Promise<IResponse>;
|
|
500
550
|
/**
|
|
@@ -556,7 +606,7 @@ export declare class ContainerRuntime extends TypedEventEmitter<IContainerRuntim
|
|
|
556
606
|
* Returns the runtime of the data store.
|
|
557
607
|
* @param id - Id supplied during creating the data store.
|
|
558
608
|
* @param wait - True if you want to wait for it.
|
|
559
|
-
* @deprecated
|
|
609
|
+
* @deprecated Use getAliasedDataStoreEntryPoint instead to get an aliased data store's entry point.
|
|
560
610
|
*/
|
|
561
611
|
getRootDataStore(id: string, wait?: boolean): Promise<IFluidRouter>;
|
|
562
612
|
private getRootDataStoreChannel;
|
|
@@ -601,9 +651,16 @@ export declare class ContainerRuntime extends TypedEventEmitter<IContainerRuntim
|
|
|
601
651
|
* Submits the signal to be sent to other clients.
|
|
602
652
|
* @param type - Type of the signal.
|
|
603
653
|
* @param content - Content of the signal.
|
|
654
|
+
* @param targetClientId - When specified, the signal is only sent to the provided client id.
|
|
655
|
+
*/
|
|
656
|
+
submitSignal(type: string, content: any, targetClientId?: string): void;
|
|
657
|
+
/**
|
|
658
|
+
* Submits the signal to be sent to other clients.
|
|
659
|
+
* @param type - Type of the signal.
|
|
660
|
+
* @param content - Content of the signal.
|
|
661
|
+
* @param targetClientId - When specified, the signal is only sent to the provided client id.
|
|
604
662
|
*/
|
|
605
|
-
|
|
606
|
-
submitDataStoreSignal(address: string, type: string, content: any): void;
|
|
663
|
+
submitDataStoreSignal(address: string, type: string, content: any, targetClientId?: string): void;
|
|
607
664
|
setAttachState(attachState: AttachState.Attaching | AttachState.Attached): void;
|
|
608
665
|
/**
|
|
609
666
|
* Create a summary. Used when attaching or serializing a detached container.
|
|
@@ -659,7 +716,7 @@ export declare class ContainerRuntime extends TypedEventEmitter<IContainerRuntim
|
|
|
659
716
|
*/
|
|
660
717
|
updateUnusedRoutes(unusedRoutes: string[]): void;
|
|
661
718
|
/**
|
|
662
|
-
* @deprecated
|
|
719
|
+
* @deprecated Replaced by deleteSweepReadyNodes.
|
|
663
720
|
*/
|
|
664
721
|
deleteUnusedNodes(unusedRoutes: string[]): string[];
|
|
665
722
|
/**
|
|
@@ -774,22 +831,19 @@ export declare class ContainerRuntime extends TypedEventEmitter<IContainerRuntim
|
|
|
774
831
|
private prefetchLatestSummaryThenClose;
|
|
775
832
|
private closeStaleSummarizer;
|
|
776
833
|
/**
|
|
777
|
-
* Downloads
|
|
834
|
+
* Downloads the latest snapshot from storage.
|
|
778
835
|
* By default, it also closes the container after downloading the snapshot. However, this may be
|
|
779
836
|
* overridden via options.
|
|
780
837
|
*/
|
|
781
|
-
private
|
|
838
|
+
private fetchLatestSnapshotFromStorage;
|
|
782
839
|
notifyAttaching(): void;
|
|
783
|
-
getPendingLocalState(props?:
|
|
784
|
-
notifyImminentClosure: boolean;
|
|
785
|
-
}): Promise<unknown>;
|
|
840
|
+
getPendingLocalState(props?: IGetPendingLocalStateProps): Promise<unknown>;
|
|
786
841
|
summarizeOnDemand(options: IOnDemandSummarizeOptions): ISummarizeResults;
|
|
787
842
|
enqueueSummarize(options: IEnqueueSummarizeOptions): EnqueueSummarizeResult;
|
|
788
843
|
/**
|
|
789
|
-
*
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
private formRequestSummarizerFn;
|
|
844
|
+
* Forms a function that will create and retrieve a Summarizer.
|
|
845
|
+
*/
|
|
846
|
+
private formCreateSummarizerFn;
|
|
793
847
|
private validateSummaryHeuristicConfiguration;
|
|
794
848
|
private get groupedBatchingEnabled();
|
|
795
849
|
}
|