@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.
Files changed (248) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/api-extractor.json +1 -1
  3. package/api-report/container-runtime.api.md +864 -0
  4. package/dist/blobManager.d.ts +4 -6
  5. package/dist/blobManager.d.ts.map +1 -1
  6. package/dist/blobManager.js +42 -56
  7. package/dist/blobManager.js.map +1 -1
  8. package/dist/connectionTelemetry.d.ts.map +1 -1
  9. package/dist/connectionTelemetry.js +75 -42
  10. package/dist/connectionTelemetry.js.map +1 -1
  11. package/dist/containerRuntime.d.ts +90 -36
  12. package/dist/containerRuntime.d.ts.map +1 -1
  13. package/dist/containerRuntime.js +125 -59
  14. package/dist/containerRuntime.js.map +1 -1
  15. package/dist/dataStore.js +2 -2
  16. package/dist/dataStore.js.map +1 -1
  17. package/dist/dataStoreContext.d.ts +8 -2
  18. package/dist/dataStoreContext.d.ts.map +1 -1
  19. package/dist/dataStoreContext.js +15 -8
  20. package/dist/dataStoreContext.js.map +1 -1
  21. package/dist/dataStoreRegistry.d.ts +3 -0
  22. package/dist/dataStoreRegistry.d.ts.map +1 -1
  23. package/dist/dataStoreRegistry.js +3 -0
  24. package/dist/dataStoreRegistry.js.map +1 -1
  25. package/dist/dataStores.d.ts +0 -2
  26. package/dist/dataStores.d.ts.map +1 -1
  27. package/dist/dataStores.js +2 -7
  28. package/dist/dataStores.js.map +1 -1
  29. package/dist/deltaManagerProxyBase.d.ts +1 -1
  30. package/dist/deltaManagerProxyBase.d.ts.map +1 -1
  31. package/dist/deltaManagerProxyBase.js +2 -2
  32. package/dist/deltaManagerProxyBase.js.map +1 -1
  33. package/dist/error.d.ts.map +1 -1
  34. package/dist/error.js.map +1 -1
  35. package/dist/gc/garbageCollection.d.ts +6 -0
  36. package/dist/gc/garbageCollection.d.ts.map +1 -1
  37. package/dist/gc/garbageCollection.js +16 -3
  38. package/dist/gc/garbageCollection.js.map +1 -1
  39. package/dist/gc/gcConfigs.d.ts +1 -0
  40. package/dist/gc/gcConfigs.d.ts.map +1 -1
  41. package/dist/gc/gcConfigs.js +12 -2
  42. package/dist/gc/gcConfigs.js.map +1 -1
  43. package/dist/gc/gcDefinitions.d.ts +42 -11
  44. package/dist/gc/gcDefinitions.d.ts.map +1 -1
  45. package/dist/gc/gcDefinitions.js +4 -1
  46. package/dist/gc/gcDefinitions.js.map +1 -1
  47. package/dist/gc/gcSummaryDefinitions.d.ts +1 -1
  48. package/dist/gc/gcSummaryDefinitions.js.map +1 -1
  49. package/dist/gc/gcTelemetry.d.ts +2 -3
  50. package/dist/gc/gcTelemetry.d.ts.map +1 -1
  51. package/dist/gc/gcTelemetry.js +7 -8
  52. package/dist/gc/gcTelemetry.js.map +1 -1
  53. package/dist/gc/index.d.ts +2 -2
  54. package/dist/gc/index.d.ts.map +1 -1
  55. package/dist/gc/index.js +1 -5
  56. package/dist/gc/index.js.map +1 -1
  57. package/dist/id-compressor/utilities.d.ts +3 -0
  58. package/dist/id-compressor/utilities.d.ts.map +1 -1
  59. package/dist/id-compressor/utilities.js +3 -0
  60. package/dist/id-compressor/utilities.js.map +1 -1
  61. package/dist/index.d.ts +4 -3
  62. package/dist/index.d.ts.map +1 -1
  63. package/dist/index.js +4 -1
  64. package/dist/index.js.map +1 -1
  65. package/dist/messageTypes.d.ts +4 -1
  66. package/dist/messageTypes.d.ts.map +1 -1
  67. package/dist/messageTypes.js +3 -0
  68. package/dist/messageTypes.js.map +1 -1
  69. package/dist/opLifecycle/definitions.d.ts +3 -0
  70. package/dist/opLifecycle/definitions.d.ts.map +1 -1
  71. package/dist/opLifecycle/definitions.js.map +1 -1
  72. package/dist/opLifecycle/outbox.d.ts.map +1 -1
  73. package/dist/opLifecycle/outbox.js +7 -2
  74. package/dist/opLifecycle/outbox.js.map +1 -1
  75. package/dist/packageVersion.d.ts +1 -1
  76. package/dist/packageVersion.js +1 -1
  77. package/dist/packageVersion.js.map +1 -1
  78. package/dist/pendingStateManager.d.ts.map +1 -1
  79. package/dist/pendingStateManager.js +3 -1
  80. package/dist/pendingStateManager.js.map +1 -1
  81. package/dist/scheduleManager.js +6 -2
  82. package/dist/scheduleManager.js.map +1 -1
  83. package/dist/summary/orderedClientElection.d.ts +4 -1
  84. package/dist/summary/orderedClientElection.d.ts.map +1 -1
  85. package/dist/summary/orderedClientElection.js.map +1 -1
  86. package/dist/summary/runWhileConnectedCoordinator.d.ts +5 -0
  87. package/dist/summary/runWhileConnectedCoordinator.d.ts.map +1 -1
  88. package/dist/summary/runWhileConnectedCoordinator.js +1 -0
  89. package/dist/summary/runWhileConnectedCoordinator.js.map +1 -1
  90. package/dist/summary/summarizer.d.ts +2 -0
  91. package/dist/summary/summarizer.d.ts.map +1 -1
  92. package/dist/summary/summarizer.js +15 -7
  93. package/dist/summary/summarizer.js.map +1 -1
  94. package/dist/summary/summarizerTypes.d.ts +94 -10
  95. package/dist/summary/summarizerTypes.d.ts.map +1 -1
  96. package/dist/summary/summarizerTypes.js.map +1 -1
  97. package/dist/summary/summaryCollection.d.ts +16 -0
  98. package/dist/summary/summaryCollection.d.ts.map +1 -1
  99. package/dist/summary/summaryCollection.js +2 -0
  100. package/dist/summary/summaryCollection.js.map +1 -1
  101. package/dist/summary/summaryFormat.d.ts +10 -1
  102. package/dist/summary/summaryFormat.d.ts.map +1 -1
  103. package/dist/summary/summaryFormat.js.map +1 -1
  104. package/dist/summary/summaryGenerator.js.map +1 -1
  105. package/dist/summary/summaryManager.d.ts +2 -2
  106. package/dist/summary/summaryManager.d.ts.map +1 -1
  107. package/dist/summary/summaryManager.js +3 -3
  108. package/dist/summary/summaryManager.js.map +1 -1
  109. package/dist/tsdoc-metadata.json +1 -1
  110. package/lib/blobManager.d.ts +4 -6
  111. package/lib/blobManager.d.ts.map +1 -1
  112. package/lib/blobManager.js +44 -58
  113. package/lib/blobManager.js.map +1 -1
  114. package/lib/connectionTelemetry.d.ts.map +1 -1
  115. package/lib/connectionTelemetry.js +76 -43
  116. package/lib/connectionTelemetry.js.map +1 -1
  117. package/lib/containerRuntime.d.ts +90 -36
  118. package/lib/containerRuntime.d.ts.map +1 -1
  119. package/lib/containerRuntime.js +125 -62
  120. package/lib/containerRuntime.js.map +1 -1
  121. package/lib/dataStore.js +2 -2
  122. package/lib/dataStore.js.map +1 -1
  123. package/lib/dataStoreContext.d.ts +8 -2
  124. package/lib/dataStoreContext.d.ts.map +1 -1
  125. package/lib/dataStoreContext.js +16 -9
  126. package/lib/dataStoreContext.js.map +1 -1
  127. package/lib/dataStoreRegistry.d.ts +3 -0
  128. package/lib/dataStoreRegistry.d.ts.map +1 -1
  129. package/lib/dataStoreRegistry.js +3 -0
  130. package/lib/dataStoreRegistry.js.map +1 -1
  131. package/lib/dataStores.d.ts +0 -2
  132. package/lib/dataStores.d.ts.map +1 -1
  133. package/lib/dataStores.js +3 -8
  134. package/lib/dataStores.js.map +1 -1
  135. package/lib/deltaManagerProxyBase.d.ts +1 -1
  136. package/lib/deltaManagerProxyBase.d.ts.map +1 -1
  137. package/lib/deltaManagerProxyBase.js +2 -2
  138. package/lib/deltaManagerProxyBase.js.map +1 -1
  139. package/lib/error.d.ts.map +1 -1
  140. package/lib/error.js.map +1 -1
  141. package/lib/gc/garbageCollection.d.ts +6 -0
  142. package/lib/gc/garbageCollection.d.ts.map +1 -1
  143. package/lib/gc/garbageCollection.js +16 -3
  144. package/lib/gc/garbageCollection.js.map +1 -1
  145. package/lib/gc/gcConfigs.d.ts +1 -0
  146. package/lib/gc/gcConfigs.d.ts.map +1 -1
  147. package/lib/gc/gcConfigs.js +14 -4
  148. package/lib/gc/gcConfigs.js.map +1 -1
  149. package/lib/gc/gcDefinitions.d.ts +42 -11
  150. package/lib/gc/gcDefinitions.d.ts.map +1 -1
  151. package/lib/gc/gcDefinitions.js +4 -1
  152. package/lib/gc/gcDefinitions.js.map +1 -1
  153. package/lib/gc/gcSummaryDefinitions.d.ts +1 -1
  154. package/lib/gc/gcSummaryDefinitions.js.map +1 -1
  155. package/lib/gc/gcTelemetry.d.ts +2 -3
  156. package/lib/gc/gcTelemetry.d.ts.map +1 -1
  157. package/lib/gc/gcTelemetry.js +7 -8
  158. package/lib/gc/gcTelemetry.js.map +1 -1
  159. package/lib/gc/index.d.ts +2 -2
  160. package/lib/gc/index.d.ts.map +1 -1
  161. package/lib/gc/index.js +2 -2
  162. package/lib/gc/index.js.map +1 -1
  163. package/lib/id-compressor/utilities.d.ts +3 -0
  164. package/lib/id-compressor/utilities.d.ts.map +1 -1
  165. package/lib/id-compressor/utilities.js +3 -0
  166. package/lib/id-compressor/utilities.js.map +1 -1
  167. package/lib/index.d.ts +4 -3
  168. package/lib/index.d.ts.map +1 -1
  169. package/lib/index.js +2 -1
  170. package/lib/index.js.map +1 -1
  171. package/lib/messageTypes.d.ts +4 -1
  172. package/lib/messageTypes.d.ts.map +1 -1
  173. package/lib/messageTypes.js +3 -0
  174. package/lib/messageTypes.js.map +1 -1
  175. package/lib/opLifecycle/definitions.d.ts +3 -0
  176. package/lib/opLifecycle/definitions.d.ts.map +1 -1
  177. package/lib/opLifecycle/definitions.js.map +1 -1
  178. package/lib/opLifecycle/outbox.d.ts.map +1 -1
  179. package/lib/opLifecycle/outbox.js +7 -2
  180. package/lib/opLifecycle/outbox.js.map +1 -1
  181. package/lib/packageVersion.d.ts +1 -1
  182. package/lib/packageVersion.js +1 -1
  183. package/lib/packageVersion.js.map +1 -1
  184. package/lib/pendingStateManager.d.ts.map +1 -1
  185. package/lib/pendingStateManager.js +3 -1
  186. package/lib/pendingStateManager.js.map +1 -1
  187. package/lib/scheduleManager.js +6 -2
  188. package/lib/scheduleManager.js.map +1 -1
  189. package/lib/summary/orderedClientElection.d.ts +4 -1
  190. package/lib/summary/orderedClientElection.d.ts.map +1 -1
  191. package/lib/summary/orderedClientElection.js.map +1 -1
  192. package/lib/summary/runWhileConnectedCoordinator.d.ts +5 -0
  193. package/lib/summary/runWhileConnectedCoordinator.d.ts.map +1 -1
  194. package/lib/summary/runWhileConnectedCoordinator.js +1 -0
  195. package/lib/summary/runWhileConnectedCoordinator.js.map +1 -1
  196. package/lib/summary/summarizer.d.ts +2 -0
  197. package/lib/summary/summarizer.d.ts.map +1 -1
  198. package/lib/summary/summarizer.js +16 -8
  199. package/lib/summary/summarizer.js.map +1 -1
  200. package/lib/summary/summarizerTypes.d.ts +94 -10
  201. package/lib/summary/summarizerTypes.d.ts.map +1 -1
  202. package/lib/summary/summarizerTypes.js.map +1 -1
  203. package/lib/summary/summaryCollection.d.ts +16 -0
  204. package/lib/summary/summaryCollection.d.ts.map +1 -1
  205. package/lib/summary/summaryCollection.js +2 -0
  206. package/lib/summary/summaryCollection.js.map +1 -1
  207. package/lib/summary/summaryFormat.d.ts +10 -1
  208. package/lib/summary/summaryFormat.d.ts.map +1 -1
  209. package/lib/summary/summaryFormat.js.map +1 -1
  210. package/lib/summary/summaryGenerator.js.map +1 -1
  211. package/lib/summary/summaryManager.d.ts +2 -2
  212. package/lib/summary/summaryManager.d.ts.map +1 -1
  213. package/lib/summary/summaryManager.js +3 -3
  214. package/lib/summary/summaryManager.js.map +1 -1
  215. package/package.json +26 -58
  216. package/src/blobManager.ts +61 -74
  217. package/src/connectionTelemetry.ts +97 -52
  218. package/src/containerRuntime.ts +173 -93
  219. package/src/dataStore.ts +2 -2
  220. package/src/dataStoreContext.ts +16 -9
  221. package/src/dataStoreRegistry.ts +3 -0
  222. package/src/dataStores.ts +4 -16
  223. package/src/deltaManagerProxyBase.ts +2 -2
  224. package/src/error.ts +4 -1
  225. package/src/gc/garbageCollection.ts +18 -3
  226. package/src/gc/gcConfigs.ts +22 -4
  227. package/src/gc/gcDefinitions.ts +43 -11
  228. package/src/gc/gcSummaryDefinitions.ts +1 -1
  229. package/src/gc/gcTelemetry.ts +8 -8
  230. package/src/gc/index.ts +0 -4
  231. package/src/id-compressor/utilities.ts +3 -0
  232. package/src/index.ts +14 -1
  233. package/src/messageTypes.ts +4 -1
  234. package/src/opLifecycle/README.md +53 -28
  235. package/src/opLifecycle/definitions.ts +3 -0
  236. package/src/opLifecycle/outbox.ts +3 -0
  237. package/src/packageVersion.ts +1 -1
  238. package/src/pendingStateManager.ts +1 -0
  239. package/src/scheduleManager.ts +2 -0
  240. package/src/summary/orderedClientElection.ts +4 -1
  241. package/src/summary/runWhileConnectedCoordinator.ts +5 -1
  242. package/src/summary/summarizer.ts +21 -9
  243. package/src/summary/summarizerTypes.ts +95 -11
  244. package/src/summary/summaryCollection.ts +19 -1
  245. package/src/summary/summaryFormat.ts +11 -1
  246. package/src/summary/summaryGenerator.ts +3 -3
  247. package/src/summary/summaryManager.ts +2 -2
  248. package/src/gc/gcEarlyAdoption.md +0 -145
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fluidframework/container-runtime",
3
- "version": "2.0.0-internal.7.0.0",
3
+ "version": "2.0.0-internal.7.2.0",
4
4
  "description": "Fluid container runtime",
5
5
  "homepage": "https://fluidframework.com",
6
6
  "repository": {
@@ -35,18 +35,18 @@
35
35
  "temp-directory": "nyc/.nyc_output"
36
36
  },
37
37
  "dependencies": {
38
- "@fluid-internal/client-utils": ">=2.0.0-internal.7.0.0 <2.0.0-internal.7.1.0",
39
- "@fluidframework/container-definitions": ">=2.0.0-internal.7.0.0 <2.0.0-internal.7.1.0",
40
- "@fluidframework/container-runtime-definitions": ">=2.0.0-internal.7.0.0 <2.0.0-internal.7.1.0",
41
- "@fluidframework/core-interfaces": ">=2.0.0-internal.7.0.0 <2.0.0-internal.7.1.0",
42
- "@fluidframework/core-utils": ">=2.0.0-internal.7.0.0 <2.0.0-internal.7.1.0",
43
- "@fluidframework/datastore": ">=2.0.0-internal.7.0.0 <2.0.0-internal.7.1.0",
44
- "@fluidframework/driver-definitions": ">=2.0.0-internal.7.0.0 <2.0.0-internal.7.1.0",
45
- "@fluidframework/driver-utils": ">=2.0.0-internal.7.0.0 <2.0.0-internal.7.1.0",
38
+ "@fluid-internal/client-utils": ">=2.0.0-internal.7.2.0 <2.0.0-internal.7.3.0",
39
+ "@fluidframework/container-definitions": ">=2.0.0-internal.7.2.0 <2.0.0-internal.7.3.0",
40
+ "@fluidframework/container-runtime-definitions": ">=2.0.0-internal.7.2.0 <2.0.0-internal.7.3.0",
41
+ "@fluidframework/core-interfaces": ">=2.0.0-internal.7.2.0 <2.0.0-internal.7.3.0",
42
+ "@fluidframework/core-utils": ">=2.0.0-internal.7.2.0 <2.0.0-internal.7.3.0",
43
+ "@fluidframework/datastore": ">=2.0.0-internal.7.2.0 <2.0.0-internal.7.3.0",
44
+ "@fluidframework/driver-definitions": ">=2.0.0-internal.7.2.0 <2.0.0-internal.7.3.0",
45
+ "@fluidframework/driver-utils": ">=2.0.0-internal.7.2.0 <2.0.0-internal.7.3.0",
46
46
  "@fluidframework/protocol-definitions": "^3.0.0",
47
- "@fluidframework/runtime-definitions": ">=2.0.0-internal.7.0.0 <2.0.0-internal.7.1.0",
48
- "@fluidframework/runtime-utils": ">=2.0.0-internal.7.0.0 <2.0.0-internal.7.1.0",
49
- "@fluidframework/telemetry-utils": ">=2.0.0-internal.7.0.0 <2.0.0-internal.7.1.0",
47
+ "@fluidframework/runtime-definitions": ">=2.0.0-internal.7.2.0 <2.0.0-internal.7.3.0",
48
+ "@fluidframework/runtime-utils": ">=2.0.0-internal.7.2.0 <2.0.0-internal.7.3.0",
49
+ "@fluidframework/telemetry-utils": ">=2.0.0-internal.7.2.0 <2.0.0-internal.7.3.0",
50
50
  "double-ended-queue": "^2.1.0-0",
51
51
  "events": "^3.1.0",
52
52
  "lz4js": "^0.2.0",
@@ -54,15 +54,15 @@
54
54
  "uuid": "^9.0.0"
55
55
  },
56
56
  "devDependencies": {
57
- "@fluid-internal/stochastic-test-utils": ">=2.0.0-internal.7.0.0 <2.0.0-internal.7.1.0",
57
+ "@fluid-internal/stochastic-test-utils": ">=2.0.0-internal.7.2.0 <2.0.0-internal.7.3.0",
58
58
  "@fluid-tools/benchmark": "^0.48.0",
59
- "@fluid-tools/build-cli": "^0.24.0",
60
- "@fluidframework/build-common": "^2.0.0",
61
- "@fluidframework/build-tools": "^0.24.0",
62
- "@fluidframework/container-runtime-previous": "npm:@fluidframework/container-runtime@2.0.0-internal.6.3.0",
63
- "@fluidframework/eslint-config-fluid": "^2.1.0",
64
- "@fluidframework/mocha-test-setup": ">=2.0.0-internal.7.0.0 <2.0.0-internal.7.1.0",
65
- "@fluidframework/test-runtime-utils": ">=2.0.0-internal.7.0.0 <2.0.0-internal.7.1.0",
59
+ "@fluid-tools/build-cli": "^0.26.1",
60
+ "@fluidframework/build-common": "^2.0.3",
61
+ "@fluidframework/build-tools": "^0.26.1",
62
+ "@fluidframework/container-runtime-previous": "npm:@fluidframework/container-runtime@2.0.0-internal.7.1.0",
63
+ "@fluidframework/eslint-config-fluid": "^3.0.0",
64
+ "@fluidframework/mocha-test-setup": ">=2.0.0-internal.7.2.0 <2.0.0-internal.7.3.0",
65
+ "@fluidframework/test-runtime-utils": ">=2.0.0-internal.7.2.0 <2.0.0-internal.7.3.0",
66
66
  "@microsoft/api-extractor": "^7.37.0",
67
67
  "@types/double-ended-queue": "^2.1.0",
68
68
  "@types/events": "^3.0.0",
@@ -70,14 +70,13 @@
70
70
  "@types/sinon": "^7.0.13",
71
71
  "@types/uuid": "^9.0.2",
72
72
  "c8": "^7.7.1",
73
- "copyfiles": "^2.4.1",
74
73
  "cross-env": "^7.0.3",
75
- "eslint": "~8.6.0",
74
+ "eslint": "~8.50.0",
76
75
  "mocha": "^10.2.0",
77
76
  "mocha-json-output-reporter": "^2.0.1",
78
77
  "mocha-multi-reporters": "^1.5.1",
79
78
  "moment": "^2.21.0",
80
- "prettier": "~2.6.2",
79
+ "prettier": "~3.0.3",
81
80
  "rimraf": "^4.4.0",
82
81
  "sinon": "^7.4.2",
83
82
  "typescript": "~5.1.6"
@@ -85,38 +84,7 @@
85
84
  "typeValidation": {
86
85
  "broken": {
87
86
  "ClassDeclaration_ContainerRuntime": {
88
- "forwardCompat": false,
89
- "backCompat": false
90
- },
91
- "InterfaceDeclaration_IAckedSummary": {
92
- "backCompat": false
93
- },
94
- "InterfaceDeclaration_IAckSummaryResult": {
95
- "backCompat": false
96
- },
97
- "InterfaceDeclaration_IBroadcastSummaryResult": {
98
- "backCompat": false
99
- },
100
- "InterfaceDeclaration_ISummaryOpMessage": {
101
- "backCompat": false
102
- },
103
- "InterfaceDeclaration_ISummaryNackMessage": {
104
- "backCompat": false
105
- },
106
- "ClassDeclaration_Summarizer": {
107
- "backCompat": false
108
- },
109
- "ClassDeclaration_SummaryCollection": {
110
- "backCompat": false
111
- },
112
- "InterfaceDeclaration_ISummarizerRuntime": {
113
- "backCompat": false
114
- },
115
- "InterfaceDeclaration_INackSummaryResult": {
116
- "backCompat": false
117
- },
118
- "InterfaceDeclaration_ISummaryAckMessage": {
119
- "backCompat": false
87
+ "forwardCompat": false
120
88
  }
121
89
  }
122
90
  },
@@ -124,12 +92,12 @@
124
92
  "build": "fluid-build . --task build",
125
93
  "build:commonjs": "fluid-build . --task commonjs",
126
94
  "build:compile": "fluid-build . --task compile",
127
- "build:docs": "api-extractor run --local --typescript-compiler-folder ../../../node_modules/typescript && copyfiles -u 1 ./_api-extractor-temp/doc-models/* ../../../_api-extractor-temp/",
95
+ "build:docs": "api-extractor run --local",
128
96
  "build:esnext": "tsc --project ./tsconfig.esnext.json",
129
97
  "build:genver": "gen-version",
130
98
  "build:test": "tsc --project ./src/test/tsconfig.json",
131
- "ci:build:docs": "api-extractor run --typescript-compiler-folder ../../../node_modules/typescript && copyfiles -u 1 ./_api-extractor-temp/doc-models/* ../../../_api-extractor-temp/",
132
- "clean": "rimraf --glob 'dist' 'lib' '*.tsbuildinfo' '*.build.log' '_api-extractor-temp' 'nyc'",
99
+ "ci:build:docs": "api-extractor run",
100
+ "clean": "rimraf --glob dist lib \"*.tsbuildinfo\" \"*.build.log\" _api-extractor-temp nyc",
133
101
  "eslint": "eslint --format stylish src",
134
102
  "eslint:fix": "eslint --format stylish src --fix --fix-type problem,suggestion,layout",
135
103
  "format": "npm run prettier:fix",
@@ -30,6 +30,7 @@ import {
30
30
  LoggingError,
31
31
  MonitoringContext,
32
32
  PerformanceEvent,
33
+ wrapError,
33
34
  } from "@fluidframework/telemetry-utils";
34
35
  import {
35
36
  IGarbageCollectionData,
@@ -37,14 +38,9 @@ import {
37
38
  ITelemetryContext,
38
39
  } from "@fluidframework/runtime-definitions";
39
40
 
41
+ import { canRetryOnError, runWithRetry } from "@fluidframework/driver-utils";
40
42
  import { ContainerRuntime, TombstoneResponseHeaderKey } from "./containerRuntime";
41
- import {
42
- sendGCUnexpectedUsageEvent,
43
- disableAttachmentBlobSweepKey,
44
- throwOnTombstoneLoadKey,
45
- } from "./gc";
46
- import { Throttler, formExponentialFn, IThrottler } from "./throttler";
47
- import { summarizerClientType } from "./summary";
43
+ import { sendGCUnexpectedUsageEvent, disableAttachmentBlobSweepKey } from "./gc";
48
44
  import { IBlobMetadata } from "./metadata";
49
45
 
50
46
  /**
@@ -88,25 +84,9 @@ export class BlobHandle implements IFluidHandle<ArrayBufferLike> {
88
84
  }
89
85
  }
90
86
 
91
- class CancellableThrottler {
92
- constructor(private readonly throttler: IThrottler) {}
93
- private cancelP = new Deferred<void>();
94
-
95
- public async getDelay(): Promise<void> {
96
- return Promise.race([
97
- this.cancelP.promise,
98
- new Promise<void>((resolve) => setTimeout(resolve, this.throttler.getDelay())),
99
- ]);
100
- }
101
-
102
- public cancel() {
103
- this.cancelP.resolve();
104
- this.cancelP = new Deferred<void>();
105
- }
106
- }
107
-
108
87
  /**
109
88
  * Information from a snapshot needed to load BlobManager
89
+ * @public
110
90
  */
111
91
  export interface IBlobManagerLoadInfo {
112
92
  ids?: string[];
@@ -119,7 +99,7 @@ export type IBlobManagerRuntime = Pick<
119
99
  IContainerRuntime,
120
100
  "attachState" | "connected" | "logger" | "clientDetails"
121
101
  > &
122
- Pick<ContainerRuntime, "gcTombstoneEnforcementAllowed"> &
102
+ Pick<ContainerRuntime, "gcTombstoneEnforcementAllowed" | "gcThrowOnTombstoneLoad"> &
123
103
  TypedEventEmitter<IContainerRuntimeEvents>;
124
104
 
125
105
  type ICreateBlobResponseWithTTL = ICreateBlobResponse & Partial<Record<"minTTLInSeconds", number>>;
@@ -180,17 +160,6 @@ export class BlobManager extends TypedEventEmitter<IBlobManagerEvents> {
180
160
  */
181
161
  private readonly opsInFlight: Map<string, string[]> = new Map();
182
162
 
183
- private readonly retryThrottler = new CancellableThrottler(
184
- new Throttler(
185
- 60 * 1000, // 60 sec delay window
186
- 30 * 1000, // 30 sec max delay
187
- // throttling function increases exponentially (0ms, 40ms, 80ms, 160ms, etc)
188
- formExponentialFn({ coefficient: 20, initialDelay: 0 }),
189
- ),
190
- );
191
-
192
- /** If true, throw an error when a tombstone attachment blob is retrieved. */
193
- private readonly throwOnTombstoneLoad: boolean;
194
163
  /**
195
164
  * This stores IDs of tombstoned blobs.
196
165
  * Tombstone is a temporary feature that imitates a blob getting swept by garbage collection.
@@ -198,6 +167,7 @@ export class BlobManager extends TypedEventEmitter<IBlobManagerEvents> {
198
167
  private readonly tombstonedBlobs: Set<string> = new Set();
199
168
 
200
169
  private readonly sendBlobAttachOp: (localId: string, storageId?: string) => void;
170
+ private stopAttaching: boolean = false;
201
171
 
202
172
  constructor(
203
173
  private readonly routeContext: IFluidHandleContext,
@@ -229,11 +199,6 @@ export class BlobManager extends TypedEventEmitter<IBlobManagerEvents> {
229
199
  logger: this.runtime.logger,
230
200
  namespace: "BlobManager",
231
201
  });
232
- // Read the feature flag that tells whether to throw when a tombstone blob is requested.
233
- this.throwOnTombstoneLoad =
234
- this.mc.config.getBoolean(throwOnTombstoneLoadKey) === true &&
235
- this.runtime.gcTombstoneEnforcementAllowed &&
236
- this.runtime.clientDetails.type !== summarizerClientType;
237
202
 
238
203
  this.redirectTable = this.load(snapshot);
239
204
 
@@ -339,7 +304,6 @@ export class BlobManager extends TypedEventEmitter<IBlobManagerEvents> {
339
304
  * Upload blobs added while offline. This must be completed before connecting and resubmitting ops.
340
305
  */
341
306
  public async processStashedChanges() {
342
- this.retryThrottler.cancel();
343
307
  const pendingUploads = Array.from(this.pendingBlobs.values())
344
308
  .filter((e) => e.pendingStashed === true)
345
309
  .map(async (e) => e.uploadP);
@@ -493,14 +457,39 @@ export class BlobManager extends TypedEventEmitter<IBlobManagerEvents> {
493
457
  localId: string,
494
458
  blob: ArrayBufferLike,
495
459
  ): Promise<ICreateBlobResponse | void> {
496
- return PerformanceEvent.timedExecAsync(
460
+ return runWithRetry(
461
+ async () => {
462
+ try {
463
+ return await this.getStorage().createBlob(blob);
464
+ } catch (error) {
465
+ const entry = this.pendingBlobs.get(localId);
466
+ assert(
467
+ !!entry,
468
+ 0x387 /* Must have pending blob entry for blob which failed to upload */,
469
+ );
470
+ if (entry.opsent && !canRetryOnError(error)) {
471
+ throw wrapError(
472
+ error,
473
+ () => new LoggingError(`uploadBlob error`, { canRetry: true }),
474
+ );
475
+ }
476
+ throw error;
477
+ }
478
+ },
479
+ "createBlob",
497
480
  this.mc.logger,
498
- { eventName: "createBlob" },
499
- async () => this.getStorage().createBlob(blob),
500
- { end: true, cancel: this.runtime.connected ? "error" : "generic" },
481
+ {
482
+ cancel: this.pendingBlobs.get(localId)?.abortSignal,
483
+ },
501
484
  ).then(
502
485
  (response) => this.onUploadResolve(localId, response),
503
- async (err) => this.onUploadReject(localId, err),
486
+ (error) => {
487
+ // it will only reject if we haven't sent an op
488
+ // and is a non-retriable error. It will only reject
489
+ // the promise but not throw any error outside.
490
+ this.pendingBlobs.get(localId)?.handleP.reject(error);
491
+ this.deletePendingBlob(localId);
492
+ },
504
493
  );
505
494
  }
506
495
 
@@ -530,7 +519,7 @@ export class BlobManager extends TypedEventEmitter<IBlobManagerEvents> {
530
519
  private onUploadResolve(localId: string, response: ICreateBlobResponseWithTTL) {
531
520
  const entry = this.pendingBlobs.get(localId);
532
521
  assert(entry !== undefined, 0x6c8 /* pending blob entry not found for uploaded blob */);
533
- if (entry.abortSignal?.aborted === true && !entry.opsent) {
522
+ if ((entry.abortSignal?.aborted === true && !entry.opsent) || this.stopAttaching) {
534
523
  this.deletePendingBlob(localId);
535
524
  return;
536
525
  }
@@ -568,25 +557,6 @@ export class BlobManager extends TypedEventEmitter<IBlobManagerEvents> {
568
557
  return response;
569
558
  }
570
559
 
571
- private async onUploadReject(localId: string, error: any) {
572
- const entry = this.pendingBlobs.get(localId);
573
- assert(!!entry, 0x387 /* Must have pending blob entry for blob which failed to upload */);
574
- if (entry.abortSignal?.aborted === true && !entry.opsent) {
575
- this.deletePendingBlob(localId);
576
- return;
577
- }
578
- if (!this.runtime.connected) {
579
- // we are probably not connected to storage but start another upload request in case we are
580
- entry.uploadP = this.retryThrottler
581
- .getDelay()
582
- .then(async () => this.uploadBlob(localId, entry.blob));
583
- return entry.uploadP;
584
- } else {
585
- entry.handleP.reject(error);
586
- throw error;
587
- }
588
- }
589
-
590
560
  /**
591
561
  * Resubmit a BlobAttach op. Used to add storage IDs to ops that were
592
562
  * submitted to runtime while disconnected.
@@ -881,7 +851,7 @@ export class BlobManager extends TypedEventEmitter<IBlobManagerEvents> {
881
851
 
882
852
  // If the blob is deleted or throw on tombstone load is enabled, throw an error which will fail any attempt
883
853
  // to load the blob.
884
- const shouldFail = state === "deleted" || this.throwOnTombstoneLoad;
854
+ const shouldFail = state === "deleted" || this.runtime.gcThrowOnTombstoneLoad;
885
855
  const request = { url: blobId };
886
856
  const error = responseToException(
887
857
  createResponseError(
@@ -930,7 +900,9 @@ export class BlobManager extends TypedEventEmitter<IBlobManagerEvents> {
930
900
  }
931
901
  }
932
902
 
933
- public async attachAndGetPendingBlobs(): Promise<IPendingBlobs | undefined> {
903
+ public async attachAndGetPendingBlobs(
904
+ stopBlobAttachingSignal?: AbortSignal,
905
+ ): Promise<IPendingBlobs | undefined> {
934
906
  return PerformanceEvent.timedExecAsync(
935
907
  this.mc.logger,
936
908
  { eventName: "GetPendingBlobs" },
@@ -945,12 +917,17 @@ export class BlobManager extends TypedEventEmitter<IBlobManagerEvents> {
945
917
  for (const [id, entry] of this.pendingBlobs) {
946
918
  if (!localBlobs.has(entry)) {
947
919
  localBlobs.add(entry);
948
- if (!entry.opsent) {
949
- this.sendBlobAttachOp(id, entry.storageId);
950
- }
951
920
  entry.handleP.resolve(this.getBlobHandle(id));
952
921
  attachBlobsP.push(
953
- new Promise<void>((resolve) => {
922
+ new Promise<void>((resolve, reject) => {
923
+ stopBlobAttachingSignal?.addEventListener(
924
+ "abort",
925
+ () => {
926
+ this.stopAttaching = true;
927
+ reject(new Error("Operation aborted"));
928
+ },
929
+ { once: true },
930
+ );
954
931
  const onBlobAttached = (attachedEntry) => {
955
932
  if (attachedEntry === entry) {
956
933
  this.off("blobAttached", onBlobAttached);
@@ -966,11 +943,21 @@ export class BlobManager extends TypedEventEmitter<IBlobManagerEvents> {
966
943
  );
967
944
  }
968
945
  }
969
- await Promise.all(attachBlobsP);
946
+ await Promise.allSettled(attachBlobsP).catch(() => {});
970
947
  }
971
948
 
972
949
  for (const [id, entry] of this.pendingBlobs) {
950
+ if (stopBlobAttachingSignal?.aborted && !entry.attached) {
951
+ this.mc.logger.sendTelemetryEvent({
952
+ eventName: "UnableToStashBlob",
953
+ id,
954
+ });
955
+ continue;
956
+ }
973
957
  assert(entry.attached === true, 0x790 /* stashed blob should be attached */);
958
+ if (!entry.opsent) {
959
+ this.sendBlobAttachOp(id, entry.storageId);
960
+ }
974
961
  blobs[id] = {
975
962
  blob: bufferToString(entry.blob, "base64"),
976
963
  storageId: entry.storageId,
@@ -4,8 +4,11 @@
4
4
  */
5
5
 
6
6
  import {
7
+ IEventSampler,
8
+ ISampledTelemetryLogger,
7
9
  ITelemetryLoggerExt,
8
10
  createChildLogger,
11
+ createSampledLogger,
9
12
  formatTick,
10
13
  } from "@fluidframework/telemetry-utils";
11
14
  import { IDeltaManager } from "@fluidframework/container-definitions";
@@ -53,7 +56,6 @@ interface IOpPerfTimings {
53
56
  }
54
57
 
55
58
  class OpPerfTelemetry {
56
- private pongCount: number = 0;
57
59
  private pingLatency: number | undefined;
58
60
 
59
61
  // Collab window tracking. This is timestamp of %1000 message.
@@ -61,11 +63,14 @@ class OpPerfTelemetry {
61
63
  private msnTrackingTimestamp: number = 0;
62
64
  // To track round trip time for every %500 client message.
63
65
  private clientSequenceNumberForLatencyStatistics: number | undefined;
64
-
65
- private opProcessingTimes: Partial<IOpPerfTimings> = {};
66
-
67
66
  // Performance Data to be reported for ops round trips and processing.
68
- private opPerfData: Partial<IOpPerfTelemetryProperties> = {};
67
+ private readonly latencyStatistics = new Map<
68
+ number,
69
+ {
70
+ opProcessingTimes: Partial<IOpPerfTimings>;
71
+ opPerfData: Partial<IOpPerfTelemetryProperties>;
72
+ }
73
+ >();
69
74
 
70
75
  private firstConnection = true;
71
76
  private connectionOpSeqNumber: number | undefined;
@@ -75,6 +80,12 @@ class OpPerfTelemetry {
75
80
 
76
81
  private readonly logger: ITelemetryLoggerExt;
77
82
 
83
+ private static readonly OP_LATENCY_SAMPLE_RATE = 500;
84
+ private readonly opLatencyLogger: ISampledTelemetryLogger;
85
+
86
+ private static readonly DELTA_LATENCY_SAMPLE_RATE = 100;
87
+ private readonly deltaLatencyLogger: ISampledTelemetryLogger;
88
+
78
89
  public constructor(
79
90
  private clientId: string | undefined,
80
91
  private readonly deltaManager: IDeltaManager<ISequencedDocumentMessage, IDocumentMessage>,
@@ -82,6 +93,28 @@ class OpPerfTelemetry {
82
93
  ) {
83
94
  this.logger = createChildLogger({ logger, namespace: "OpPerf" });
84
95
 
96
+ const deltaLatencyEventSampler: IEventSampler = (() => {
97
+ let eventCount = -1;
98
+ return {
99
+ sample: () => {
100
+ eventCount++;
101
+ const shouldSample =
102
+ eventCount % OpPerfTelemetry.DELTA_LATENCY_SAMPLE_RATE === 0;
103
+ if (shouldSample) {
104
+ eventCount = 0;
105
+ }
106
+ return shouldSample;
107
+ },
108
+ };
109
+ })();
110
+
111
+ this.deltaLatencyLogger = createSampledLogger(logger, deltaLatencyEventSampler);
112
+
113
+ // The SampledLogger here is used get access to the isSamplingDisabled property dervied from
114
+ // telemetry config properties. The actual sampling logic for op messages happens outside this SampledLogger
115
+ // due to complexity of the different asynchronus scenarios of the op message lifecycle.
116
+ this.opLatencyLogger = createSampledLogger(logger);
117
+
85
118
  this.deltaManager.on("pong", (latency) => this.recordPingTime(latency));
86
119
  this.deltaManager.on("submitOp", (message) => this.beforeOpSubmit(message));
87
120
 
@@ -103,42 +136,47 @@ class OpPerfTelemetry {
103
136
  this.deltaManager.on("disconnect", () => {
104
137
  this.sequenceNumberForMsnTracking = undefined;
105
138
  this.clientSequenceNumberForLatencyStatistics = undefined;
106
- this.opProcessingTimes = {};
107
- this.opPerfData = {};
108
139
  this.connectionOpSeqNumber = undefined;
109
140
  this.firstConnection = false;
110
- this.pongCount = 0;
141
+ this.latencyStatistics.clear();
111
142
  });
112
143
 
113
144
  this.deltaManager.outbound.on("push", (messages) => {
114
145
  for (const msg of messages) {
115
146
  if (
116
147
  msg.type === MessageType.Operation &&
117
- this.clientSequenceNumberForLatencyStatistics === msg.clientSequenceNumber
148
+ (this.opLatencyLogger.isSamplingDisabled ||
149
+ this.clientSequenceNumberForLatencyStatistics === msg.clientSequenceNumber)
118
150
  ) {
151
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
152
+ const latencyStats = this.latencyStatistics.get(msg.clientSequenceNumber)!;
153
+ assert(
154
+ latencyStats !== undefined,
155
+ 0x7c2 /* Latency stats for op should exist */,
156
+ );
119
157
  assert(
120
- this.opProcessingTimes.outboundPushEventTime === undefined,
158
+ latencyStats.opProcessingTimes.outboundPushEventTime === undefined,
121
159
  0x2c8 /* "outboundPushEventTime should be undefined" */,
122
160
  );
123
161
  assert(
124
- this.opPerfData.durationNetwork === undefined,
162
+ latencyStats.opPerfData.durationNetwork === undefined,
125
163
  0x2c9 /* "durationNetwork should be undefined" */,
126
164
  );
127
- this.opProcessingTimes.outboundPushEventTime = Date.now();
165
+ latencyStats.opProcessingTimes.outboundPushEventTime = Date.now();
128
166
 
129
167
  assert(
130
- this.opPerfData.durationOutboundBatching === undefined,
168
+ latencyStats.opPerfData.durationOutboundBatching === undefined,
131
169
  0x2ca /* "durationOutboundBatching should be undefined" */,
132
170
  );
133
171
 
134
172
  assert(
135
- this.opProcessingTimes.submitOpEventTime !== undefined,
173
+ latencyStats.opProcessingTimes.submitOpEventTime !== undefined,
136
174
  0x2cb /* "submitOpEventTime should be undefined" */,
137
175
  );
138
176
 
139
- this.opPerfData.durationOutboundBatching =
140
- this.opProcessingTimes.outboundPushEventTime -
141
- this.opProcessingTimes.submitOpEventTime;
177
+ latencyStats.opPerfData.durationOutboundBatching =
178
+ latencyStats.opProcessingTimes.outboundPushEventTime -
179
+ latencyStats.opProcessingTimes.submitOpEventTime;
142
180
  }
143
181
  }
144
182
  });
@@ -147,15 +185,20 @@ class OpPerfTelemetry {
147
185
  if (
148
186
  this.clientId === message.clientId &&
149
187
  message.type === MessageType.Operation &&
150
- this.clientSequenceNumberForLatencyStatistics === message.clientSequenceNumber &&
151
- this.opProcessingTimes.outboundPushEventTime !== undefined
188
+ (this.opLatencyLogger.isSamplingDisabled ||
189
+ this.clientSequenceNumberForLatencyStatistics === message.clientSequenceNumber)
152
190
  ) {
153
- this.opProcessingTimes.inboundPushEventTime = Date.now();
154
- this.opPerfData.durationNetwork =
155
- this.opProcessingTimes.inboundPushEventTime -
156
- this.opProcessingTimes.outboundPushEventTime;
157
- this.opProcessingTimes.outboundPushEventTime = undefined;
158
- this.opPerfData.lengthInboundQueue = this.deltaManager.inbound.length;
191
+ // We do an explicit check for undefined right after this
192
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
193
+ const latencyStats = this.latencyStatistics.get(message.clientSequenceNumber)!;
194
+ assert(latencyStats !== undefined, 0x7c3 /* Latency stats for op should exist */);
195
+ if (latencyStats.opProcessingTimes.outboundPushEventTime !== undefined) {
196
+ latencyStats.opProcessingTimes.inboundPushEventTime = Date.now();
197
+ latencyStats.opPerfData.durationNetwork =
198
+ latencyStats.opProcessingTimes.inboundPushEventTime -
199
+ latencyStats.opProcessingTimes.outboundPushEventTime;
200
+ latencyStats.opPerfData.lengthInboundQueue = this.deltaManager.inbound.length;
201
+ }
159
202
  }
160
203
  });
161
204
 
@@ -201,32 +244,33 @@ class OpPerfTelemetry {
201
244
  });
202
245
  }
203
246
 
204
- // logging one in every 100 pongs, including the first time, if it is a "write" client.
205
- if (this.pongCount % 100 === 0 && this.deltaManager.active) {
206
- this.logger.sendPerformanceEvent({
247
+ // logging one in every DELTA_LATENCY_SAMPLE_RATE pongs, including the first time, if it is a "write" client.
248
+ if (this.deltaManager.active) {
249
+ this.deltaLatencyLogger.sendPerformanceEvent({
207
250
  eventName: "DeltaLatency",
208
251
  duration: latency,
209
252
  });
210
253
  }
211
- this.pongCount++;
212
254
  }
213
255
 
214
256
  private beforeOpSubmit(message: IDocumentMessage) {
215
257
  // start with first client op and measure latency every 500 client ops
216
258
  if (
217
- this.clientSequenceNumberForLatencyStatistics === undefined &&
218
- message.clientSequenceNumber % 500 === 1
259
+ this.opLatencyLogger.isSamplingDisabled ||
260
+ (this.clientSequenceNumberForLatencyStatistics === undefined &&
261
+ message.clientSequenceNumber % OpPerfTelemetry.OP_LATENCY_SAMPLE_RATE === 1)
219
262
  ) {
220
263
  assert(
221
- this.opProcessingTimes.outboundPushEventTime === undefined,
222
- 0x2cc /* "OpTimeSittingInboundQueue should be undefined" */,
223
- );
224
- assert(
225
- this.opPerfData.durationNetwork === undefined,
226
- 0x2cd /* "durationNetwork should be undefined" */,
264
+ this.latencyStatistics.get(message.clientSequenceNumber) === undefined,
265
+ 0x7c4 /* Existing op perf data for client sequence number */,
227
266
  );
228
- this.opProcessingTimes.submitOpEventTime = Date.now();
229
267
  this.clientSequenceNumberForLatencyStatistics = message.clientSequenceNumber;
268
+ this.latencyStatistics.set(message.clientSequenceNumber, {
269
+ opProcessingTimes: {
270
+ submitOpEventTime: Date.now(),
271
+ },
272
+ opPerfData: {},
273
+ });
230
274
  }
231
275
  }
232
276
 
@@ -261,20 +305,23 @@ class OpPerfTelemetry {
261
305
 
262
306
  if (
263
307
  this.clientId === message.clientId &&
264
- this.clientSequenceNumberForLatencyStatistics === message.clientSequenceNumber
308
+ (this.opLatencyLogger.isSamplingDisabled ||
309
+ this.clientSequenceNumberForLatencyStatistics === message.clientSequenceNumber)
265
310
  ) {
311
+ // We do an explicit check for undefined right after this
312
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
313
+ const latencyData = this.latencyStatistics.get(message.clientSequenceNumber)!;
314
+ assert(latencyData !== undefined, 0x7c5 /* Undefined latency statistics for op */);
266
315
  assert(
267
- this.opProcessingTimes.submitOpEventTime !== undefined,
268
- 0x120 /* "Undefined latency statistics (op send time)" */,
316
+ latencyData.opProcessingTimes.submitOpEventTime !== undefined,
317
+ 0x120 /* "Undefined latency statistics for op (op send time)" */,
269
318
  );
270
319
  const currentTime = Date.now();
271
-
272
- if (this.opProcessingTimes.inboundPushEventTime !== undefined) {
273
- this.opPerfData.durationInboundToProcessing =
274
- currentTime - this.opProcessingTimes.inboundPushEventTime;
320
+ if (latencyData.opProcessingTimes.inboundPushEventTime !== undefined) {
321
+ latencyData.opPerfData.durationInboundToProcessing =
322
+ currentTime - latencyData.opProcessingTimes.inboundPushEventTime;
275
323
  }
276
-
277
- const duration = currentTime - this.opProcessingTimes.submitOpEventTime;
324
+ const duration = currentTime - latencyData.opProcessingTimes.submitOpEventTime;
278
325
 
279
326
  // One of the core expectations for Fluid service is to be fast.
280
327
  // When it's not the case, we want to learn about it and be able to investigate, so
@@ -284,8 +331,7 @@ class OpPerfTelemetry {
284
331
  // The threshold could be adjusted, but ideally it stays workload-agnostic, as service
285
332
  // performance impacts all workloads relying on service.
286
333
  const category = duration > latencyThreshold ? "error" : "performance";
287
-
288
- this.logger.sendPerformanceEvent({
334
+ this.opLatencyLogger.sendPerformanceEvent({
289
335
  eventName: "OpRoundtripTime",
290
336
  sequenceNumber,
291
337
  referenceSequenceNumber: message.referenceSequenceNumber,
@@ -294,11 +340,10 @@ class OpPerfTelemetry {
294
340
  pingLatency: this.pingLatency,
295
341
  msnDistance:
296
342
  this.deltaManager.lastSequenceNumber - this.deltaManager.minimumSequenceNumber,
297
- ...this.opPerfData,
343
+ ...latencyData.opPerfData,
298
344
  });
299
345
  this.clientSequenceNumberForLatencyStatistics = undefined;
300
- this.opPerfData = {};
301
- this.opProcessingTimes = {};
346
+ this.latencyStatistics.delete(message.clientSequenceNumber);
302
347
  }
303
348
  }
304
349
  }