@fluidframework/container-runtime 2.0.0-dev.6.4.0.191515 → 2.0.0-dev.7.2.0.203917

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 (335) hide show
  1. package/CHANGELOG.md +119 -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 -4
  5. package/dist/blobManager.d.ts.map +1 -1
  6. package/dist/blobManager.js +55 -71
  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/container-runtime-alpha.d.ts +1742 -0
  12. package/dist/container-runtime-beta.d.ts +1742 -0
  13. package/dist/container-runtime-public.d.ts +1742 -0
  14. package/dist/container-runtime-untrimmed.d.ts +1803 -0
  15. package/dist/containerHandleContext.js +3 -3
  16. package/dist/containerHandleContext.js.map +1 -1
  17. package/dist/containerRuntime.d.ts +88 -98
  18. package/dist/containerRuntime.d.ts.map +1 -1
  19. package/dist/containerRuntime.js +466 -453
  20. package/dist/containerRuntime.js.map +1 -1
  21. package/dist/dataStore.js +11 -11
  22. package/dist/dataStore.js.map +1 -1
  23. package/dist/dataStoreContext.d.ts +2 -4
  24. package/dist/dataStoreContext.d.ts.map +1 -1
  25. package/dist/dataStoreContext.js +60 -59
  26. package/dist/dataStoreContext.js.map +1 -1
  27. package/dist/dataStoreRegistry.d.ts +3 -0
  28. package/dist/dataStoreRegistry.d.ts.map +1 -1
  29. package/dist/dataStoreRegistry.js +6 -3
  30. package/dist/dataStoreRegistry.js.map +1 -1
  31. package/dist/dataStores.js +1 -1
  32. package/dist/dataStores.js.map +1 -1
  33. package/dist/deltaManagerProxyBase.js +4 -4
  34. package/dist/deltaManagerProxyBase.js.map +1 -1
  35. package/dist/deltaManagerSummarizerProxy.js +6 -6
  36. package/dist/deltaManagerSummarizerProxy.js.map +1 -1
  37. package/dist/deltaScheduler.js.map +1 -1
  38. package/dist/error.d.ts.map +1 -1
  39. package/dist/error.js.map +1 -1
  40. package/dist/gc/garbageCollection.d.ts.map +1 -1
  41. package/dist/gc/garbageCollection.js +23 -24
  42. package/dist/gc/garbageCollection.js.map +1 -1
  43. package/dist/gc/gcConfigs.js +1 -1
  44. package/dist/gc/gcConfigs.js.map +1 -1
  45. package/dist/gc/gcDefinitions.d.ts +34 -24
  46. package/dist/gc/gcDefinitions.d.ts.map +1 -1
  47. package/dist/gc/gcDefinitions.js +10 -7
  48. package/dist/gc/gcDefinitions.js.map +1 -1
  49. package/dist/gc/gcSummaryDefinitions.d.ts +1 -1
  50. package/dist/gc/gcSummaryDefinitions.js.map +1 -1
  51. package/dist/gc/gcTelemetry.d.ts +2 -2
  52. package/dist/gc/gcTelemetry.d.ts.map +1 -1
  53. package/dist/gc/gcTelemetry.js +5 -5
  54. package/dist/gc/gcTelemetry.js.map +1 -1
  55. package/dist/gc/gcUnreferencedStateTracker.js +3 -3
  56. package/dist/gc/gcUnreferencedStateTracker.js.map +1 -1
  57. package/dist/gc/index.d.ts +1 -1
  58. package/dist/gc/index.d.ts.map +1 -1
  59. package/dist/gc/index.js +3 -3
  60. package/dist/gc/index.js.map +1 -1
  61. package/dist/id-compressor/appendOnlySortedMap.js.map +1 -1
  62. package/dist/id-compressor/idCompressor.js.map +1 -1
  63. package/dist/id-compressor/identifiers.d.ts +3 -3
  64. package/dist/id-compressor/identifiers.d.ts.map +1 -1
  65. package/dist/id-compressor/utilities.d.ts +3 -0
  66. package/dist/id-compressor/utilities.d.ts.map +1 -1
  67. package/dist/id-compressor/utilities.js +3 -0
  68. package/dist/id-compressor/utilities.js.map +1 -1
  69. package/dist/index.d.ts +5 -3
  70. package/dist/index.d.ts.map +1 -1
  71. package/dist/index.js +6 -2
  72. package/dist/index.js.map +1 -1
  73. package/dist/messageTypes.d.ts +137 -0
  74. package/dist/messageTypes.d.ts.map +1 -0
  75. package/dist/messageTypes.js +32 -0
  76. package/dist/messageTypes.js.map +1 -0
  77. package/dist/opLifecycle/batchManager.js +6 -6
  78. package/dist/opLifecycle/batchManager.js.map +1 -1
  79. package/dist/opLifecycle/definitions.d.ts +7 -3
  80. package/dist/opLifecycle/definitions.d.ts.map +1 -1
  81. package/dist/opLifecycle/definitions.js.map +1 -1
  82. package/dist/opLifecycle/opDecompressor.d.ts.map +1 -1
  83. package/dist/opLifecycle/opDecompressor.js +0 -4
  84. package/dist/opLifecycle/opDecompressor.js.map +1 -1
  85. package/dist/opLifecycle/opGroupingManager.d.ts.map +1 -1
  86. package/dist/opLifecycle/opGroupingManager.js.map +1 -1
  87. package/dist/opLifecycle/opSplitter.js +3 -3
  88. package/dist/opLifecycle/opSplitter.js.map +1 -1
  89. package/dist/opLifecycle/outbox.d.ts.map +1 -1
  90. package/dist/opLifecycle/outbox.js +7 -2
  91. package/dist/opLifecycle/outbox.js.map +1 -1
  92. package/dist/opLifecycle/remoteMessageProcessor.d.ts +17 -3
  93. package/dist/opLifecycle/remoteMessageProcessor.d.ts.map +1 -1
  94. package/dist/opLifecycle/remoteMessageProcessor.js +38 -25
  95. package/dist/opLifecycle/remoteMessageProcessor.js.map +1 -1
  96. package/dist/packageVersion.d.ts +1 -1
  97. package/dist/packageVersion.js +1 -1
  98. package/dist/packageVersion.js.map +1 -1
  99. package/dist/pendingStateManager.d.ts +4 -20
  100. package/dist/pendingStateManager.d.ts.map +1 -1
  101. package/dist/pendingStateManager.js +36 -46
  102. package/dist/pendingStateManager.js.map +1 -1
  103. package/dist/scheduleManager.js +6 -2
  104. package/dist/scheduleManager.js.map +1 -1
  105. package/dist/summary/orderedClientElection.d.ts +7 -4
  106. package/dist/summary/orderedClientElection.d.ts.map +1 -1
  107. package/dist/summary/orderedClientElection.js +54 -54
  108. package/dist/summary/orderedClientElection.js.map +1 -1
  109. package/dist/summary/runWhileConnectedCoordinator.d.ts +5 -0
  110. package/dist/summary/runWhileConnectedCoordinator.d.ts.map +1 -1
  111. package/dist/summary/runWhileConnectedCoordinator.js +7 -6
  112. package/dist/summary/runWhileConnectedCoordinator.js.map +1 -1
  113. package/dist/summary/runningSummarizer.d.ts.map +1 -1
  114. package/dist/summary/runningSummarizer.js +40 -38
  115. package/dist/summary/runningSummarizer.js.map +1 -1
  116. package/dist/summary/summarizer.d.ts +2 -0
  117. package/dist/summary/summarizer.d.ts.map +1 -1
  118. package/dist/summary/summarizer.js +18 -8
  119. package/dist/summary/summarizer.js.map +1 -1
  120. package/dist/summary/summarizerClientElection.js +6 -6
  121. package/dist/summary/summarizerClientElection.js.map +1 -1
  122. package/dist/summary/summarizerHeuristics.js +9 -9
  123. package/dist/summary/summarizerHeuristics.js.map +1 -1
  124. package/dist/summary/summarizerNode/summarizerNode.d.ts +1 -1
  125. package/dist/summary/summarizerNode/summarizerNode.js +8 -8
  126. package/dist/summary/summarizerNode/summarizerNode.js.map +1 -1
  127. package/dist/summary/summarizerNode/summarizerNodeUtils.d.ts +1 -1
  128. package/dist/summary/summarizerNode/summarizerNodeUtils.d.ts.map +1 -1
  129. package/dist/summary/summarizerNode/summarizerNodeUtils.js +3 -3
  130. package/dist/summary/summarizerNode/summarizerNodeUtils.js.map +1 -1
  131. package/dist/summary/summarizerNode/summarizerNodeWithGc.d.ts +2 -2
  132. package/dist/summary/summarizerNode/summarizerNodeWithGc.d.ts.map +1 -1
  133. package/dist/summary/summarizerTypes.d.ts +107 -22
  134. package/dist/summary/summarizerTypes.d.ts.map +1 -1
  135. package/dist/summary/summarizerTypes.js.map +1 -1
  136. package/dist/summary/summaryCollection.d.ts +18 -2
  137. package/dist/summary/summaryCollection.d.ts.map +1 -1
  138. package/dist/summary/summaryCollection.js +23 -21
  139. package/dist/summary/summaryCollection.js.map +1 -1
  140. package/dist/summary/summaryFormat.d.ts +15 -6
  141. package/dist/summary/summaryFormat.d.ts.map +1 -1
  142. package/dist/summary/summaryFormat.js.map +1 -1
  143. package/dist/summary/summaryGenerator.d.ts +3 -3
  144. package/dist/summary/summaryGenerator.d.ts.map +1 -1
  145. package/dist/summary/summaryGenerator.js.map +1 -1
  146. package/dist/summary/summaryManager.d.ts +2 -2
  147. package/dist/summary/summaryManager.d.ts.map +1 -1
  148. package/dist/summary/summaryManager.js +10 -10
  149. package/dist/summary/summaryManager.js.map +1 -1
  150. package/dist/throttler.js +16 -16
  151. package/dist/throttler.js.map +1 -1
  152. package/dist/tsdoc-metadata.json +1 -1
  153. package/lib/blobManager.d.ts +4 -4
  154. package/lib/blobManager.d.ts.map +1 -1
  155. package/lib/blobManager.js +56 -72
  156. package/lib/blobManager.js.map +1 -1
  157. package/lib/connectionTelemetry.d.ts.map +1 -1
  158. package/lib/connectionTelemetry.js +76 -43
  159. package/lib/connectionTelemetry.js.map +1 -1
  160. package/lib/containerHandleContext.js +3 -3
  161. package/lib/containerHandleContext.js.map +1 -1
  162. package/lib/containerRuntime.d.ts +88 -98
  163. package/lib/containerRuntime.d.ts.map +1 -1
  164. package/lib/containerRuntime.js +424 -416
  165. package/lib/containerRuntime.js.map +1 -1
  166. package/lib/dataStore.js +11 -11
  167. package/lib/dataStore.js.map +1 -1
  168. package/lib/dataStoreContext.d.ts +2 -4
  169. package/lib/dataStoreContext.d.ts.map +1 -1
  170. package/lib/dataStoreContext.js +60 -59
  171. package/lib/dataStoreContext.js.map +1 -1
  172. package/lib/dataStoreRegistry.d.ts +3 -0
  173. package/lib/dataStoreRegistry.d.ts.map +1 -1
  174. package/lib/dataStoreRegistry.js +6 -3
  175. package/lib/dataStoreRegistry.js.map +1 -1
  176. package/lib/dataStores.js +1 -1
  177. package/lib/dataStores.js.map +1 -1
  178. package/lib/deltaManagerProxyBase.js +4 -4
  179. package/lib/deltaManagerProxyBase.js.map +1 -1
  180. package/lib/deltaManagerSummarizerProxy.js +6 -6
  181. package/lib/deltaManagerSummarizerProxy.js.map +1 -1
  182. package/lib/deltaScheduler.js.map +1 -1
  183. package/lib/error.d.ts.map +1 -1
  184. package/lib/error.js.map +1 -1
  185. package/lib/gc/garbageCollection.d.ts.map +1 -1
  186. package/lib/gc/garbageCollection.js +23 -24
  187. package/lib/gc/garbageCollection.js.map +1 -1
  188. package/lib/gc/gcConfigs.js +2 -2
  189. package/lib/gc/gcConfigs.js.map +1 -1
  190. package/lib/gc/gcDefinitions.d.ts +34 -24
  191. package/lib/gc/gcDefinitions.d.ts.map +1 -1
  192. package/lib/gc/gcDefinitions.js +9 -6
  193. package/lib/gc/gcDefinitions.js.map +1 -1
  194. package/lib/gc/gcSummaryDefinitions.d.ts +1 -1
  195. package/lib/gc/gcSummaryDefinitions.js.map +1 -1
  196. package/lib/gc/gcTelemetry.d.ts +2 -2
  197. package/lib/gc/gcTelemetry.d.ts.map +1 -1
  198. package/lib/gc/gcTelemetry.js +5 -5
  199. package/lib/gc/gcTelemetry.js.map +1 -1
  200. package/lib/gc/gcUnreferencedStateTracker.js +3 -3
  201. package/lib/gc/gcUnreferencedStateTracker.js.map +1 -1
  202. package/lib/gc/index.d.ts +1 -1
  203. package/lib/gc/index.d.ts.map +1 -1
  204. package/lib/gc/index.js +1 -1
  205. package/lib/gc/index.js.map +1 -1
  206. package/lib/id-compressor/appendOnlySortedMap.js.map +1 -1
  207. package/lib/id-compressor/idCompressor.js.map +1 -1
  208. package/lib/id-compressor/identifiers.d.ts +3 -3
  209. package/lib/id-compressor/identifiers.d.ts.map +1 -1
  210. package/lib/id-compressor/utilities.d.ts +3 -0
  211. package/lib/id-compressor/utilities.d.ts.map +1 -1
  212. package/lib/id-compressor/utilities.js +3 -0
  213. package/lib/id-compressor/utilities.js.map +1 -1
  214. package/lib/index.d.ts +5 -3
  215. package/lib/index.d.ts.map +1 -1
  216. package/lib/index.js +3 -1
  217. package/lib/index.js.map +1 -1
  218. package/lib/messageTypes.d.ts +137 -0
  219. package/lib/messageTypes.d.ts.map +1 -0
  220. package/lib/messageTypes.js +29 -0
  221. package/lib/messageTypes.js.map +1 -0
  222. package/lib/opLifecycle/batchManager.js +6 -6
  223. package/lib/opLifecycle/batchManager.js.map +1 -1
  224. package/lib/opLifecycle/definitions.d.ts +7 -3
  225. package/lib/opLifecycle/definitions.d.ts.map +1 -1
  226. package/lib/opLifecycle/definitions.js.map +1 -1
  227. package/lib/opLifecycle/opDecompressor.d.ts.map +1 -1
  228. package/lib/opLifecycle/opDecompressor.js +0 -4
  229. package/lib/opLifecycle/opDecompressor.js.map +1 -1
  230. package/lib/opLifecycle/opGroupingManager.d.ts.map +1 -1
  231. package/lib/opLifecycle/opGroupingManager.js.map +1 -1
  232. package/lib/opLifecycle/opSplitter.js +1 -1
  233. package/lib/opLifecycle/opSplitter.js.map +1 -1
  234. package/lib/opLifecycle/outbox.d.ts.map +1 -1
  235. package/lib/opLifecycle/outbox.js +7 -2
  236. package/lib/opLifecycle/outbox.js.map +1 -1
  237. package/lib/opLifecycle/remoteMessageProcessor.d.ts +17 -3
  238. package/lib/opLifecycle/remoteMessageProcessor.d.ts.map +1 -1
  239. package/lib/opLifecycle/remoteMessageProcessor.js +37 -24
  240. package/lib/opLifecycle/remoteMessageProcessor.js.map +1 -1
  241. package/lib/packageVersion.d.ts +1 -1
  242. package/lib/packageVersion.js +1 -1
  243. package/lib/packageVersion.js.map +1 -1
  244. package/lib/pendingStateManager.d.ts +4 -20
  245. package/lib/pendingStateManager.d.ts.map +1 -1
  246. package/lib/pendingStateManager.js +35 -45
  247. package/lib/pendingStateManager.js.map +1 -1
  248. package/lib/scheduleManager.js +6 -2
  249. package/lib/scheduleManager.js.map +1 -1
  250. package/lib/summary/orderedClientElection.d.ts +7 -4
  251. package/lib/summary/orderedClientElection.d.ts.map +1 -1
  252. package/lib/summary/orderedClientElection.js +54 -54
  253. package/lib/summary/orderedClientElection.js.map +1 -1
  254. package/lib/summary/runWhileConnectedCoordinator.d.ts +5 -0
  255. package/lib/summary/runWhileConnectedCoordinator.d.ts.map +1 -1
  256. package/lib/summary/runWhileConnectedCoordinator.js +7 -6
  257. package/lib/summary/runWhileConnectedCoordinator.js.map +1 -1
  258. package/lib/summary/runningSummarizer.d.ts.map +1 -1
  259. package/lib/summary/runningSummarizer.js +40 -38
  260. package/lib/summary/runningSummarizer.js.map +1 -1
  261. package/lib/summary/summarizer.d.ts +2 -0
  262. package/lib/summary/summarizer.d.ts.map +1 -1
  263. package/lib/summary/summarizer.js +19 -9
  264. package/lib/summary/summarizer.js.map +1 -1
  265. package/lib/summary/summarizerClientElection.js +6 -6
  266. package/lib/summary/summarizerClientElection.js.map +1 -1
  267. package/lib/summary/summarizerHeuristics.js +9 -9
  268. package/lib/summary/summarizerHeuristics.js.map +1 -1
  269. package/lib/summary/summarizerNode/summarizerNode.d.ts +1 -1
  270. package/lib/summary/summarizerNode/summarizerNode.js +8 -8
  271. package/lib/summary/summarizerNode/summarizerNode.js.map +1 -1
  272. package/lib/summary/summarizerNode/summarizerNodeUtils.d.ts +1 -1
  273. package/lib/summary/summarizerNode/summarizerNodeUtils.d.ts.map +1 -1
  274. package/lib/summary/summarizerNode/summarizerNodeUtils.js +3 -3
  275. package/lib/summary/summarizerNode/summarizerNodeUtils.js.map +1 -1
  276. package/lib/summary/summarizerNode/summarizerNodeWithGc.d.ts +2 -2
  277. package/lib/summary/summarizerNode/summarizerNodeWithGc.d.ts.map +1 -1
  278. package/lib/summary/summarizerTypes.d.ts +107 -22
  279. package/lib/summary/summarizerTypes.d.ts.map +1 -1
  280. package/lib/summary/summarizerTypes.js.map +1 -1
  281. package/lib/summary/summaryCollection.d.ts +18 -2
  282. package/lib/summary/summaryCollection.d.ts.map +1 -1
  283. package/lib/summary/summaryCollection.js +23 -21
  284. package/lib/summary/summaryCollection.js.map +1 -1
  285. package/lib/summary/summaryFormat.d.ts +15 -6
  286. package/lib/summary/summaryFormat.d.ts.map +1 -1
  287. package/lib/summary/summaryFormat.js.map +1 -1
  288. package/lib/summary/summaryGenerator.d.ts +3 -3
  289. package/lib/summary/summaryGenerator.d.ts.map +1 -1
  290. package/lib/summary/summaryGenerator.js.map +1 -1
  291. package/lib/summary/summaryManager.d.ts +2 -2
  292. package/lib/summary/summaryManager.d.ts.map +1 -1
  293. package/lib/summary/summaryManager.js +9 -9
  294. package/lib/summary/summaryManager.js.map +1 -1
  295. package/lib/throttler.js +16 -16
  296. package/lib/throttler.js.map +1 -1
  297. package/package.json +27 -28
  298. package/src/blobManager.ts +64 -77
  299. package/src/connectionTelemetry.ts +97 -52
  300. package/src/containerRuntime.ts +337 -341
  301. package/src/dataStore.ts +3 -3
  302. package/src/dataStoreContext.ts +7 -7
  303. package/src/dataStoreRegistry.ts +3 -0
  304. package/src/dataStores.ts +1 -1
  305. package/src/error.ts +4 -1
  306. package/src/gc/garbageCollection.ts +12 -11
  307. package/src/gc/gcConfigs.ts +3 -3
  308. package/src/gc/gcDefinitions.ts +35 -25
  309. package/src/gc/gcSummaryDefinitions.ts +1 -1
  310. package/src/gc/gcTelemetry.ts +6 -5
  311. package/src/gc/index.ts +2 -2
  312. package/src/id-compressor/utilities.ts +3 -0
  313. package/src/index.ts +21 -5
  314. package/src/messageTypes.ts +228 -0
  315. package/src/opLifecycle/README.md +93 -68
  316. package/src/opLifecycle/definitions.ts +5 -1
  317. package/src/opLifecycle/opDecompressor.ts +0 -8
  318. package/src/opLifecycle/opGroupingManager.ts +2 -4
  319. package/src/opLifecycle/opSplitter.ts +2 -2
  320. package/src/opLifecycle/outbox.ts +3 -0
  321. package/src/opLifecycle/remoteMessageProcessor.ts +54 -33
  322. package/src/packageVersion.ts +1 -1
  323. package/src/pendingStateManager.ts +31 -52
  324. package/src/scheduleManager.ts +2 -0
  325. package/src/summary/orderedClientElection.ts +4 -1
  326. package/src/summary/runWhileConnectedCoordinator.ts +5 -1
  327. package/src/summary/runningSummarizer.ts +3 -1
  328. package/src/summary/summarizer.ts +21 -7
  329. package/src/summary/summarizerNode/summarizerNode.ts +1 -1
  330. package/src/summary/summarizerTypes.ts +96 -11
  331. package/src/summary/summaryCollection.ts +19 -1
  332. package/src/summary/summaryFormat.ts +11 -1
  333. package/src/summary/summaryGenerator.ts +3 -3
  334. package/src/summary/summaryManager.ts +2 -2
  335. package/src/gc/gcEarlyAdoption.md +0 -145
@@ -1,5 +1,19 @@
1
1
  # Configs and feature gates for solving the 1MB limit.
2
2
 
3
+ ## Table of contents
4
+
5
+ - [Introduction](#introduction)
6
+ - [How batching works](#how-batching-works)
7
+ - [Compression](#compression)
8
+ - [Grouped batching](#grouped-batching)
9
+ - [Risks](#risks)
10
+ - [Chunking for compression](#chunking-for-compression)
11
+ - [Disabling in case of emergency](#disabling-in-case-of-emergency)
12
+ - [Example configs](#example-configs)
13
+ - [Note about performance and latency](#note-about-performance-and-latency)
14
+ - [How it works](#how-it-works)
15
+ - [How grouped batching works](#how-grouped-batching-works)
16
+
3
17
  ## Introduction
4
18
 
5
19
  There is a current limitation regarding the size of the payload a Fluid client can send and receive. [The limit is 1MB per payload](https://github.com/microsoft/FluidFramework/issues/9023) and it is currently enforced explicitly with the `BatchTooLarge` error which closes the container.
@@ -8,17 +22,35 @@ There are two features which can be used to work around this size limit, batch c
8
22
 
9
23
  By default, the runtime is configured with a max batch size of `716800` bytes, which is lower than the 1MB limit. The reason for the lower value is to account for possible overhead from the op envelope and metadata.
10
24
 
11
- ## Table of contents
25
+ ### How batching works
12
26
 
13
- - [Introduction](#introduction)
14
- - [Compression](#compression)
15
- - [Grouped batching](#grouped-batching)
16
- - [Risks](#risks)
17
- - [Chunking for compression](#chunking-for-compression)
18
- - [Disabling in case of emergency](#disabling-in-case-of-emergency)
19
- - [Example configs](#example-configs)
20
- - [How it works](#how-it-works)
21
- - [How grouped batching works](#how-grouped-batching-works)
27
+ Batching in the context of Fluid ops is a way in which the framework accumulates and applies ops. A batch is a group of ops accumulated within a single JS turn, which will be broadcasted in the same order to all the other connected clients and applied synchronously. Additional logic and validation ensure that batches are never interleaved, nested or interrupted and they are processed in isolation without interleaving of ops from other clients.
28
+
29
+ The way batches are formed is governed by the `FlushMode` setting of the `ContainerRuntimeOptions` and it is immutable for the entire lifetime of the runtime and subsequently the container.
30
+
31
+ ```
32
+ export enum FlushMode {
33
+ /**
34
+ * In Immediate flush mode the runtime will immediately send all operations to the driver layer.
35
+ */
36
+ Immediate,
37
+
38
+ /**
39
+ * When in TurnBased flush mode the runtime will buffer operations in the current turn and send them as a single
40
+ * batch at the end of the turn. The flush call on the runtime can be used to force send the current batch.
41
+ */
42
+ TurnBased,
43
+ }
44
+ ```
45
+
46
+ What this means is that `FlushMode.Immediate` will send each op in its own payload to the server, while `FlushMode.TurnBased` will accumulate all ops in a single JS turn and send them together in the same payload. Technically, `FlushMode.Immediate` can be simulated with `FlushMode.TurnBased` by interrupting the JS turn after producing only one op (for example by pausing the execution to wait on a promise). Therefore, for all intents and purposes, `FlushMode.Immediate` enables all batches to have only one op.
47
+
48
+ **By default, Fluid uses `FlushMode.TurnBased`** as:
49
+
50
+ - it is more efficient from an I/O perspective (batching ops overall decrease the number of payloads sent to the server)
51
+ - reduces concurrency related bugs, as it ensures that all ops generated within the same JS turn are also applied by all other clients within a single JS turn. Clients using the same pattern can safely assume ops will be applied exactly as they are observed locally. The alternative would be for ops to be both produced and applied with interruptions (which may involve processing input or rendering), invalidating the state based off which the changes were produced.
52
+
53
+ As `FlushMode.TurnBased` accumulates ops, it is the most vulnerable to run into the 1MB socket limit.
22
54
 
23
55
  ## Compression
24
56
 
@@ -29,6 +61,8 @@ By default, the runtime is configured with a max batch size of `716800` bytes, w
29
61
  - `minimumBatchSizeInBytes` – the minimum size of the batch for which compression should kick in. If the payload is too small, compression may not yield too many benefits. To target the original 1MB issue, a good value here would be to match the default maxBatchSizeInBytes (972800), however, experimentally, a good lower value could be at around 614400 bytes. Setting this value to `Number.POSITIVE_INFINITY` will disable compression.
30
62
  - `compressionAlgorithm` – currently, only `lz4` is supported.
31
63
 
64
+ Compression is relevant for both `FlushMode.TurnBased` and `FlushMode.Immediate` as it only targets the contents of the ops and not the number of ops in a batch. Compression is opaque to the server and implementations of the Fluid protocol do not need to alter their behavior to support this client feature.
65
+
32
66
  ## Grouped batching
33
67
 
34
68
  **Note: This feature is currently considered experimental and is not ready for production usage.**
@@ -71,6 +105,8 @@ If all prerequisites in the previous section are met, enabling the feature can b
71
105
 
72
106
  In case of emergency grouped batching can be disabled at runtime, using feature gates. If `"Fluid.ContainerRuntime.DisableGroupedBatching"` is set to `true`, it will disable grouped batching if enabled from `IContainerRuntimeOptions` in the code.
73
107
 
108
+ Grouped batching is only relevant for `FlushMode.TurnBased` as it only targets the number of ops in a batch. Grouped batching is opaque to the server and implementations of the Fluid protocol do not need to alter their behavior to support this client feature.
109
+
74
110
  ## Chunking for compression
75
111
 
76
112
  **Op chunking for compression targets payloads which exceed the max batch size after compression.** So, only payloads which are already compressed. By default, the feature is enabled.
@@ -79,6 +115,8 @@ The `IContainerRuntimeOptions.chunkSizeInBytes` property is the only configurati
79
115
 
80
116
  This config would govern chunking compressed batches only. We will not be enabling chunking across all types of ops/batches but **only when compression is enabled and when the batch is compressed**, and its payload size is more than `IContainerRuntimeOptions.chunkSizeInBytes`.
81
117
 
118
+ Chunking is relevant for both `FlushMode.TurnBased` and `FlushMode.Immediate` as it only targets the contents of the ops and not the number of ops in a batch. Chunking is opaque to the server and implementations of the Fluid protocol do not need to alter their behavior to support this client feature.
119
+
82
120
  ## Disabling in case of emergency
83
121
 
84
122
  If the features are enabled using the configs, they can be disabled at runtime via feature gates as following:
@@ -102,32 +140,19 @@ By default, the runtime is configured with the following values related to compr
102
140
      }
103
141
  ```
104
142
 
105
- To use compression but disable chunking:
143
+ To enable grouped batching, use the following property:
106
144
 
107
145
  ```
108
146
  const runtimeOptions: IContainerRuntimeOptions = {
109
- chunkSizeInBytes: Number.POSITIVE_INFINITY,
147
+ enableGroupedBatching: true,
110
148
      }
111
149
  ```
112
150
 
113
- To disable compression (will also disable chunking, as chunking works only for compressed batches):
151
+ ## Note about performance and latency
114
152
 
115
- ```
116
- const runtimeOptions: IContainerRuntimeOptions = {
117
- compressionOptions: {
118
- minimumBatchSizeInBytes: Number.POSITIVE_INFINITY,
119
- compressionAlgorithm: CompressionAlgorithms.lz4,
120
- },
121
-     }
122
- ```
153
+ In terms of performance and impact on latency, the results greatly depend on payload size, payload structure, network speed and CPU speed. Therefore, customers must perform the required measurements and adjust the settings according to their scenarios.
123
154
 
124
- To enable grouped batching:
125
-
126
- ```
127
- const runtimeOptions: IContainerRuntimeOptions = {
128
- enableGroupedBatching: true,
129
-     }
130
- ```
155
+ In general, compression offers a trade-off between higher compute costs, lower bandwidth consumption and lower storage requirements, while chunking slightly increases latency due to the overhead of splitting an op, sending the chunks and reconstructing them on each client. Grouped batching heavily decreases the number of ops observed by the server and slightly decreases the bandwidth requirements as it merges all the ops in a batch into a single op and also eliminates the op envelope overhead.
131
156
 
132
157
  ## How it works
133
158
 
@@ -212,8 +237,6 @@ On the receiving end, the client will accumulate chunks 1 and 2 and keep them in
212
237
 
213
238
  ## How grouped batching works
214
239
 
215
- **Note: There are plans to replace empty ops with something more efficient when doing grouped batching AB#4092**
216
-
217
240
  Given the following baseline batch:
218
241
 
219
242
  ```
@@ -223,68 +246,70 @@ Given the following baseline batch:
223
246
  +---------------+---------------+---------------+---------------+---------------+
224
247
  ```
225
248
 
226
- Compressed batch:
249
+ Grouped batch:
227
250
 
228
251
  ```
229
- +--------------------+-----------------+-----------------+-----------------+-----------------+
230
- | Op 1 | Op 2 | Op 3 | Op 4 | Op 5 |
231
- | Contents: "abcde" | Contents: empty | Contents: empty | Contents: empty | Contents: empty |
232
- | Compression: 'lz4' | | | | |
233
- +--------------------+-----------------+-----------------+-----------------+-----------------+
252
+ +---------------------------------------------------------------------------------------------------------------------+
253
+ | Op 1 Contents: +----------------+---------------+---------------+---------------+---------------+ |
254
+ | Type: "groupedBatch" | Op 1 | Op 2 | Op 3 | Op 4 | Op 5 | |
255
+ | | Contents: "a" | Contents: "b" | Contents: "c" | Contents: "d" | Contents: "e" | |
256
+ | +----------------+---------------+---------------+---------------+---------------+ |
257
+ +---------------------------------------------------------------------------------------------------------------------+
234
258
  ```
235
259
 
236
- Grouped batch:
260
+ Compressed batch:
237
261
 
238
262
  ```
239
- +---------------------------------------------------------------------------------------------------------------------------------+
240
- | Op 1 Contents: +--------------------+-----------------+-----------------+-----------------+-----------------+ |
241
- | SeqNum: 1 | Op 1 | Op 2 | Op 3 | Op 4 | Op 5 | |
242
- | Type: "groupedBatch" | Contents: "abcde" | Contents: empty | Contents: empty | Contents: empty | Contents: empty | |
243
- | | Compression: 'lz4' | | | | | |
244
- | +--------------------+-----------------+-----------------+-----------------+-----------------+ |
245
- +---------------------------------------------------------------------------------------------------------------------------------+
263
+ +-------------------------------------------------------------------------------------------------------------------------+
264
+ | Op 1 Contents: +------------------------------------------------------------------------------------+ |
265
+ | Compression: 'lz4' | Type: "groupedBatch" | |
266
+ | | +----------------+---------------+---------------+---------------+---------------+ | |
267
+ | | | Op 1 | Op 2 | Op 3 | Op 4 | Op 5 | | |
268
+ | | | Contents: "a" | Contents: "b" | Contents: "c" | Contents: "d" | Contents: "e" | | |
269
+ | | +----------------+---------------+---------------+---------------+---------------+ | |
270
+ | +------------------------------------------------------------------------------------+ |
271
+ +-------------------------------------------------------------------------------------------------------------------------+
246
272
  ```
247
273
 
248
274
  Can produce the following chunks:
249
275
 
250
276
  ```
251
- +-------------------------------------------------+
252
- | Chunk 1/2 Contents: +----------------------+ |
253
- | SeqNum: 1 | +-----------------+ | |
254
- | | | Contents: "abc" | | |
255
- | | +-----------------+ | |
256
- | +----------------------+ |
257
- +-------------------------------------------------+
277
+ +------------------------------------------------+
278
+ | Chunk 1/2 Contents: +---------------------+ |
279
+ | | +-----------------+ | |
280
+ | | | Contents: "abc" | | |
281
+ | | +-----------------+ | |
282
+ | +---------------------+ |
283
+ +------------------------------------------------+
258
284
  ```
259
285
 
260
286
  ```
261
- +--------------------------------------------------------------------------------------------------------------------------+
262
- | Chunk 2/2 Contents: +---------------------------------------------------------------------------------------------+ | |
263
- | SeqNum: 2 | +----------------+-----------------+-----------------+-----------------+-----------------+ | | |
264
- | | | Contents: "de" | Contents: empty | Contents: empty | Contents: empty | Contents: empty | | | |
265
- | | +----------------+-----------------+-----------------+-----------------+-----------------+ | | |
266
- | +---------------------------------------------------------------------------------------------+ | |
267
- +--------------------------------------------------------------------------------------------------------------------------+
287
+ +-----------------------------------------------+
288
+ | Chunk 2/2 Contents: +--------------------+ |
289
+ | | +----------------+ | |
290
+ | | | Contents: "de" | | |
291
+ | | +----------------+ | |
292
+ | +--------------------+ |
293
+ +-----------------------------------------------+
268
294
  ```
269
295
 
270
296
  - Send to service
271
297
  - Service acks ops sent
272
298
  - Receive chunks from service
273
- - Recompile to the grouped batch step
299
+ - Recompile to the compression step
274
300
 
275
- Ungrouped batch:
301
+ Decompressed batch:
276
302
 
277
303
  ```
278
- +--------------------+-----------------+-----------------+-----------------+-----------------+
279
- | Op 1 | Op 2 | Op 3 | Op 4 | Op 5 |
280
- | Contents: "abcde" | Contents: empty | Contents: empty | Contents: empty | Contents: empty |
281
- | SeqNum: 2 | SeqNum: 2 | SeqNum: 2 | SeqNum: 2 | SeqNum: 2 |
282
- | ClientSeqNum: 1 | ClientSeqNum: 2 | ClientSeqNum: 3 | ClientSeqNum: 4 | ClientSeqNum: 5 |
283
- | Compression: 'lz4' | | | | |
284
- +--------------------+-----------------+-----------------+-----------------+-----------------+
304
+ +---------------------------------------------------------------------------------------------------------------------+
305
+ | Op 1 Contents: +----------------+---------------+---------------+---------------+---------------+ |
306
+ | SeqNum: 2 | Op 1 | Op 2 | Op 3 | Op 4 | Op 5 | |
307
+ | Type: "groupedBatch" | Contents: "a" | Contents: "b" | Contents: "c" | Contents: "d" | Contents: "e" | |
308
+ | +----------------+---------------+---------------+---------------+---------------+ |
309
+ +---------------------------------------------------------------------------------------------------------------------+
285
310
  ```
286
311
 
287
- Uncompressed batch:
312
+ Ungrouped batch:
288
313
 
289
314
  ```
290
315
  +-----------------+-----------------+-----------------+-----------------+-----------------+
@@ -5,7 +5,8 @@
5
5
 
6
6
  import { IBatchMessage } from "@fluidframework/container-definitions";
7
7
  import { ISequencedDocumentMessage, MessageType } from "@fluidframework/protocol-definitions";
8
- import { CompressionAlgorithms, ContainerMessageType } from "..";
8
+ import { CompressionAlgorithms } from "..";
9
+ import { ContainerMessageType } from "../messageTypes";
9
10
 
10
11
  /**
11
12
  * Batch message type used internally by the runtime
@@ -51,6 +52,9 @@ export interface IBatchCheckpoint {
51
52
  rollback: (action: (message: BatchMessage) => void) => void;
52
53
  }
53
54
 
55
+ /**
56
+ * @public
57
+ */
54
58
  export interface IChunkedOp {
55
59
  chunkId: number;
56
60
  totalChunks: number;
@@ -50,14 +50,6 @@ export class OpDecompressor {
50
50
  ) {
51
51
  // Beginning of a compressed batch
52
52
  assert(this.activeBatch === false, 0x4b8 /* shouldn't have multiple active batches */);
53
- if (message.compression) {
54
- // lz4 is the only supported compression algorithm for now
55
- assert(
56
- message.compression === CompressionAlgorithms.lz4,
57
- 0x4b9 /* lz4 is currently the only supported compression algorithm */,
58
- );
59
- }
60
-
61
53
  this.activeBatch = true;
62
54
 
63
55
  const contents = IsoBuffer.from(
@@ -5,7 +5,7 @@
5
5
 
6
6
  import { assert } from "@fluidframework/core-utils";
7
7
  import { ISequencedDocumentMessage } from "@fluidframework/protocol-definitions";
8
- import { ContainerMessageType } from "..";
8
+ import { ContainerMessageType } from "../messageTypes";
9
9
  import { IBatch } from "./definitions";
10
10
 
11
11
  /**
@@ -22,9 +22,7 @@ interface IGroupedMessage {
22
22
  compression?: string;
23
23
  }
24
24
 
25
- function isGroupContents(
26
- opContents: IGroupedBatchMessageContents | { type?: unknown } | undefined,
27
- ): opContents is IGroupedBatchMessageContents {
25
+ function isGroupContents(opContents: any): opContents is IGroupedBatchMessageContents {
28
26
  return opContents?.type === OpGroupingManager.groupedBatchOp;
29
27
  }
30
28
 
@@ -12,7 +12,7 @@ import { assert } from "@fluidframework/core-utils";
12
12
  import { IBatchMessage } from "@fluidframework/container-definitions";
13
13
  import { ISequencedDocumentMessage } from "@fluidframework/protocol-definitions";
14
14
  import { ITelemetryBaseLogger } from "@fluidframework/core-interfaces";
15
- import { ContainerMessageType, ContainerRuntimeMessage } from "../containerRuntime";
15
+ import { ContainerMessageType, ContainerRuntimeChunkedOpMessage } from "../messageTypes";
16
16
  import { estimateSocketSize } from "./batchManager";
17
17
  import { BatchMessage, IBatch, IChunkedOp, IMessageProcessingResult } from "./definitions";
18
18
 
@@ -210,7 +210,7 @@ const chunkToBatchMessage = (
210
210
  referenceSequenceNumber: number,
211
211
  metadata: Record<string, unknown> | undefined = undefined,
212
212
  ): BatchMessage => {
213
- const payload: ContainerRuntimeMessage = {
213
+ const payload: ContainerRuntimeChunkedOpMessage = {
214
214
  type: ContainerMessageType.ChunkedOp,
215
215
  contents: chunk,
216
216
  };
@@ -65,10 +65,13 @@ export interface IOutboxParameters {
65
65
  export function getLongStack<T>(action: () => T, length: number = 50): T {
66
66
  const errorObj = Error as any;
67
67
  if (
68
+ /* eslint-disable @typescript-eslint/prefer-nullish-coalescing */
69
+ // ?? is not logically equivalent when the first clause returns false.
68
70
  (
69
71
  Object.getOwnPropertyDescriptor(errorObj, "stackTraceLimit") ||
70
72
  Object.getOwnPropertyDescriptor(Object.getPrototypeOf(errorObj), "stackTraceLimit")
71
73
  )?.writable !== true
74
+ /* eslint-enable @typescript-eslint/prefer-nullish-coalescing */
72
75
  ) {
73
76
  return action();
74
77
  }
@@ -6,13 +6,21 @@
6
6
  import { ISequencedDocumentMessage, MessageType } from "@fluidframework/protocol-definitions";
7
7
  import {
8
8
  ContainerMessageType,
9
- ContainerRuntimeMessage,
10
- SequencedContainerRuntimeMessage,
11
- } from "../containerRuntime";
9
+ type InboundContainerRuntimeMessage,
10
+ type InboundSequencedContainerRuntimeMessage,
11
+ type InboundSequencedContainerRuntimeMessageOrSystemMessage,
12
+ type InboundSequencedRecentlyAddedContainerRuntimeMessage,
13
+ } from "../messageTypes";
12
14
  import { OpDecompressor } from "./opDecompressor";
13
15
  import { OpGroupingManager } from "./opGroupingManager";
14
16
  import { OpSplitter } from "./opSplitter";
15
17
 
18
+ /**
19
+ * Stateful class for processing incoming remote messages as the virtualization measures are unwrapped,
20
+ * potentially across numerous inbound ops.
21
+ *
22
+ * @internal
23
+ */
16
24
  export class RemoteMessageProcessor {
17
25
  constructor(
18
26
  private readonly opSplitter: OpSplitter,
@@ -30,14 +38,25 @@ export class RemoteMessageProcessor {
30
38
 
31
39
  /**
32
40
  * Ungroups and Unchunks the runtime ops encapsulated by the single remoteMessage received over the wire
33
- * @param remoteMessage - A message from another client, likely a chunked/grouped op
34
- * @returns the ungrouped, unchunked, unpacked SequencedContainerRuntimeMessage encapsulated in the remote message
41
+ * @param remoteMessageCopy - A shallow copy of a message from another client, possibly virtualized
42
+ * (grouped, compressed, and/or chunked).
43
+ * Being a shallow copy, it's considered mutable, meaning no other Container or other parallel procedure
44
+ * depends on this object instance.
45
+ * Note remoteMessageCopy.contents (and other object props) MUST not be modified,
46
+ * but may be overwritten (as is the case with contents).
47
+ * @returns the unchunked, decompressed, ungrouped, unpacked SequencedContainerRuntimeMessages encapsulated in the remote message.
48
+ * For ops that weren't virtualized (e.g. System ops that the ContainerRuntime will ultimately ignore),
49
+ * a singleton array [remoteMessageCopy] is returned
35
50
  */
36
- public process(remoteMessage: ISequencedDocumentMessage): ISequencedDocumentMessage[] {
37
- const result: ISequencedDocumentMessage[] = [];
51
+ public process(
52
+ remoteMessageCopy: ISequencedDocumentMessage,
53
+ ): InboundSequencedContainerRuntimeMessageOrSystemMessage[] {
54
+ const result: InboundSequencedContainerRuntimeMessageOrSystemMessage[] = [];
55
+
56
+ ensureContentsDeserialized(remoteMessageCopy);
38
57
 
39
58
  // Ungroup before and after decompression for back-compat (cleanup tracked by AB#4371)
40
- for (const ungroupedMessage of this.opGroupingManager.ungroupOp(copy(remoteMessage))) {
59
+ for (const ungroupedMessage of this.opGroupingManager.ungroupOp(remoteMessageCopy)) {
41
60
  const message = this.opDecompressor.processMessage(ungroupedMessage).message;
42
61
 
43
62
  for (let ungroupedMessage2 of this.opGroupingManager.ungroupOp(message)) {
@@ -50,7 +69,9 @@ export class RemoteMessageProcessor {
50
69
  if (chunkProcessingResult.state !== "Processed") {
51
70
  // If the message is not chunked or if the splitter is still rebuilding the original message,
52
71
  // there is no need to continue processing
53
- result.push(ungroupedMessage2);
72
+ result.push(
73
+ ungroupedMessage2 as InboundSequencedContainerRuntimeMessageOrSystemMessage,
74
+ );
54
75
  continue;
55
76
  }
56
77
 
@@ -68,7 +89,9 @@ export class RemoteMessageProcessor {
68
89
  if (decompressionAfterChunking.state === "Skipped") {
69
90
  // After chunking, if the original message was not compressed,
70
91
  // there is no need to continue processing
71
- result.push(ungroupedMessageAfterChunking2);
92
+ result.push(
93
+ ungroupedMessageAfterChunking2 as InboundSequencedContainerRuntimeMessageOrSystemMessage,
94
+ );
72
95
  continue;
73
96
  }
74
97
 
@@ -84,40 +107,38 @@ export class RemoteMessageProcessor {
84
107
  }
85
108
  }
86
109
 
87
- const copy = (remoteMessage: ISequencedDocumentMessage): ISequencedDocumentMessage => {
88
- // Do shallow copy of message, as the processing flow will modify it.
89
- // There might be multiple container instances receiving same message
90
- // We do not need to make deep copy, as each layer will just replace message.content itself,
91
- // but would not modify contents details
92
- const message = { ...remoteMessage };
93
-
110
+ /** Takes an incoming message and if the contents is a string, JSON.parse's it in place */
111
+ function ensureContentsDeserialized(mutableMessage: ISequencedDocumentMessage): void {
94
112
  // back-compat: ADO #1385: eventually should become unconditional, but only for runtime messages!
95
113
  // System message may have no contents, or in some cases (mostly for back-compat) they may have actual objects.
96
114
  // Old ops may contain empty string (I assume noops).
97
- if (typeof message.contents === "string" && message.contents !== "") {
98
- message.contents = JSON.parse(message.contents);
115
+ if (typeof mutableMessage.contents === "string" && mutableMessage.contents !== "") {
116
+ mutableMessage.contents = JSON.parse(mutableMessage.contents);
99
117
  }
100
-
101
- return message;
102
- };
118
+ }
103
119
 
104
120
  /**
105
- * For a given message, it moves the nested ContainerRuntimeMessage props one level up.
121
+ * For a given message, it moves the nested InboundContainerRuntimeMessage props one level up.
106
122
  *
107
123
  * The return type illustrates the assumption that the message param
108
- * becomes a ContainerRuntimeMessage by the time the function returns
109
- * (but there is no runtime validation of the 'type' or 'compatDetails' values)
124
+ * becomes a InboundSequencedContainerRuntimeMessage by the time the function returns
125
+ * (but there is no runtime validation of the 'type' or 'compatDetails' values).
110
126
  */
111
127
  function unpack(
112
128
  message: ISequencedDocumentMessage,
113
- ): asserts message is SequencedContainerRuntimeMessage {
114
- const innerContents = message.contents as ContainerRuntimeMessage;
115
-
116
- // We're going to turn message into a SequencedContainerRuntimeMessage in-place
117
- const sequencedContainerRuntimeMessage = message as SequencedContainerRuntimeMessage;
118
- sequencedContainerRuntimeMessage.type = innerContents.type;
119
- sequencedContainerRuntimeMessage.contents = innerContents.contents;
120
- sequencedContainerRuntimeMessage.compatDetails = innerContents.compatDetails;
129
+ ): asserts message is InboundSequencedContainerRuntimeMessage {
130
+ // We assume the contents is an InboundContainerRuntimeMessage (the message is "packed")
131
+ const contents = message.contents as InboundContainerRuntimeMessage;
132
+
133
+ // We're going to unpack message in-place (promoting those properties of contents up to message itself)
134
+ const messageUnpacked = message as InboundSequencedContainerRuntimeMessage;
135
+
136
+ messageUnpacked.type = contents.type;
137
+ messageUnpacked.contents = contents.contents;
138
+ if ("compatDetails" in contents) {
139
+ (messageUnpacked as InboundSequencedRecentlyAddedContainerRuntimeMessage).compatDetails =
140
+ contents.compatDetails;
141
+ }
121
142
  }
122
143
 
123
144
  /**
@@ -6,4 +6,4 @@
6
6
  */
7
7
 
8
8
  export const pkgName = "@fluidframework/container-runtime";
9
- export const pkgVersion = "2.0.0-dev.6.4.0.191515";
9
+ export const pkgVersion = "2.0.0-dev.7.2.0.203917";
@@ -11,28 +11,15 @@ import { ICriticalContainerError } from "@fluidframework/container-definitions";
11
11
  import { ISequencedDocumentMessage } from "@fluidframework/protocol-definitions";
12
12
  import { DataProcessingError, ITelemetryLoggerExt } from "@fluidframework/telemetry-utils";
13
13
 
14
- import { ContainerMessageType, SequencedContainerRuntimeMessage } from "./containerRuntime";
14
+ import { ContainerMessageType, InboundSequencedContainerRuntimeMessage } from "./messageTypes";
15
15
  import { pkgVersion } from "./packageVersion";
16
16
  import { IBatchMetadata } from "./metadata";
17
17
 
18
- /**
19
- * ! TODO: Remove this interface in "2.0.0-internal.7.0.0" once we only read IPendingMessageNew (AB#4763)
20
- */
21
- export interface IPendingMessageOld {
22
- type: "message";
23
- messageType: ContainerMessageType;
24
- clientSequenceNumber: number;
25
- referenceSequenceNumber: number;
26
- content: any;
27
- localOpMetadata: unknown;
28
- opMetadata: Record<string, unknown> | undefined;
29
- }
30
-
31
18
  /**
32
19
  * This represents a message that has been submitted and is added to the pending queue when `submit` is called on the
33
20
  * ContainerRuntime. This message has either not been ack'd by the server or has not been submitted to the server yet.
34
21
  */
35
- export interface IPendingMessageNew {
22
+ export interface IPendingMessage {
36
23
  type: "message";
37
24
  clientSequenceNumber: number;
38
25
  referenceSequenceNumber: number;
@@ -41,16 +28,11 @@ export interface IPendingMessageNew {
41
28
  opMetadata: Record<string, unknown> | undefined;
42
29
  }
43
30
 
44
- /**
45
- * ! TODO: Remove this type in "2.0.0-internal.7.0.0" (AB#4763)
46
- */
47
- export type IPendingState = IPendingMessageOld | IPendingMessageNew;
48
-
49
31
  export interface IPendingLocalState {
50
32
  /**
51
33
  * list of pending states, including ops and batch information
52
34
  */
53
- pendingStates: IPendingState[];
35
+ pendingStates: IPendingMessage[];
54
36
  }
55
37
 
56
38
  export interface IPendingBatchMessage {
@@ -69,6 +51,26 @@ export interface IRuntimeStateHandler {
69
51
  isActiveConnection: () => boolean;
70
52
  }
71
53
 
54
+ /** Union of keys of T */
55
+ type KeysOfUnion<T extends object> = T extends T ? keyof T : never;
56
+ /** *Partial* type all possible combinations of properties and values of union T.
57
+ * This loosens typing allowing access to all possible properties without
58
+ * narrowing.
59
+ */
60
+ type AnyComboFromUnion<T extends object> = { [P in KeysOfUnion<T>]?: T[P] };
61
+
62
+ function buildPendingMessageContent(
63
+ // AnyComboFromUnion is needed need to gain access to compatDetails that
64
+ // is only defined for some cases.
65
+ message: AnyComboFromUnion<InboundSequencedContainerRuntimeMessage>,
66
+ ): string {
67
+ // IMPORTANT: Order matters here, this must match the order of the properties used
68
+ // when submitting the message.
69
+ const { type, contents, compatDetails } = message;
70
+ // Any properties that are not defined, won't be emitted by stringify.
71
+ return JSON.stringify({ type, contents, compatDetails });
72
+ }
73
+
72
74
  /**
73
75
  * PendingStateManager is responsible for maintaining the messages that have not been sent or have not yet been
74
76
  * acknowledged by the server. It also maintains the batch information for both automatically and manually flushed
@@ -79,13 +81,13 @@ export interface IRuntimeStateHandler {
79
81
  * It verifies that all the ops are acked, are received in the right order and batch information is correct.
80
82
  */
81
83
  export class PendingStateManager implements IDisposable {
82
- private readonly pendingMessages = new Deque<IPendingMessageNew>();
83
- private readonly initialMessages = new Deque<IPendingMessageNew>();
84
+ private readonly pendingMessages = new Deque<IPendingMessage>();
85
+ private readonly initialMessages = new Deque<IPendingMessage>();
84
86
 
85
87
  /**
86
88
  * Sequenced local ops that are saved when stashing since pending ops may depend on them
87
89
  */
88
- private savedOps: IPendingMessageNew[] = [];
90
+ private savedOps: IPendingMessage[] = [];
89
91
 
90
92
  private readonly disposeOnce = new Lazy<void>(() => {
91
93
  this.initialMessages.clear();
@@ -149,29 +151,8 @@ export class PendingStateManager implements IDisposable {
149
151
  initialLocalState: IPendingLocalState | undefined,
150
152
  private readonly logger: ITelemetryLoggerExt | undefined,
151
153
  ) {
152
- /**
153
- * Convert old local state format to the new format (IPendingMessageOld to IPendingMessageNew)
154
- * ! TODO: Remove this conversion in "2.0.0-internal.7.0.0" (AB#4763)
155
- */
156
154
  if (initialLocalState?.pendingStates) {
157
- for (const initialState of initialLocalState.pendingStates) {
158
- let messageContent = initialState.content;
159
- if (
160
- (initialState as IPendingMessageOld).messageType !== undefined &&
161
- typeof initialState.content !== "string"
162
- ) {
163
- // Convert IPendingMessageOld to IPendingMessageNew
164
- messageContent = JSON.stringify({
165
- type: (initialState as IPendingMessageOld).messageType,
166
- contents: initialState.content,
167
- });
168
- }
169
- // Note: this object may contain "messageType" prop, but it should not be easily accesible due to interface being used
170
- this.initialMessages.push({
171
- ...initialState,
172
- content: messageContent,
173
- });
174
- }
155
+ this.initialMessages.push(...initialLocalState.pendingStates);
175
156
  }
176
157
  }
177
158
 
@@ -193,7 +174,7 @@ export class PendingStateManager implements IDisposable {
193
174
  localOpMetadata: unknown,
194
175
  opMetadata: Record<string, unknown> | undefined,
195
176
  ) {
196
- const pendingMessage: IPendingMessageNew = {
177
+ const pendingMessage: IPendingMessage = {
197
178
  type: "message",
198
179
  clientSequenceNumber: -1, // dummy value (not to be used anywhere)
199
180
  referenceSequenceNumber,
@@ -242,7 +223,7 @@ export class PendingStateManager implements IDisposable {
242
223
  * the batch information was preserved for batch messages.
243
224
  * @param message - The message that got ack'd and needs to be processed.
244
225
  */
245
- public processPendingLocalMessage(message: SequencedContainerRuntimeMessage): unknown {
226
+ public processPendingLocalMessage(message: InboundSequencedContainerRuntimeMessage): unknown {
246
227
  // Pre-processing part - This may be the start of a batch.
247
228
  this.maybeProcessBatchBegin(message);
248
229
 
@@ -256,10 +237,7 @@ export class PendingStateManager implements IDisposable {
256
237
 
257
238
  this.pendingMessages.shift();
258
239
 
259
- // IMPORTANT: Order matters here, this must match the order of the properties used
260
- // when submitting the message.
261
- const { type, contents, compatDetails } = message;
262
- const messageContent = JSON.stringify({ type, contents, compatDetails });
240
+ const messageContent = buildPendingMessageContent(message);
263
241
 
264
242
  // Stringified content should match
265
243
  if (pendingMessage.content !== messageContent) {
@@ -340,6 +318,7 @@ export class PendingStateManager implements IDisposable {
340
318
  {
341
319
  runtimeVersion: pkgVersion,
342
320
  batchClientId:
321
+ // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
343
322
  this.pendingBatchBeginMessage.clientId === null
344
323
  ? "null"
345
324
  : this.pendingBatchBeginMessage.clientId,