@fluidframework/container-runtime 2.0.0-internal.6.1.0 → 2.0.0-internal.6.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 (363) hide show
  1. package/CHANGELOG.md +35 -0
  2. package/README.md +4 -3
  3. package/dist/batchTracker.d.ts +1 -1
  4. package/dist/batchTracker.js +1 -1
  5. package/dist/batchTracker.js.map +1 -1
  6. package/dist/blobManager.d.ts +4 -20
  7. package/dist/blobManager.d.ts.map +1 -1
  8. package/dist/blobManager.js +47 -125
  9. package/dist/blobManager.js.map +1 -1
  10. package/dist/containerRuntime.d.ts +82 -14
  11. package/dist/containerRuntime.d.ts.map +1 -1
  12. package/dist/containerRuntime.js +236 -138
  13. package/dist/containerRuntime.js.map +1 -1
  14. package/dist/dataStore.d.ts.map +1 -1
  15. package/dist/dataStore.js +1 -2
  16. package/dist/dataStore.js.map +1 -1
  17. package/dist/dataStoreContext.d.ts.map +1 -1
  18. package/dist/dataStoreContext.js +4 -5
  19. package/dist/dataStoreContext.js.map +1 -1
  20. package/dist/dataStoreContexts.d.ts +1 -2
  21. package/dist/dataStoreContexts.d.ts.map +1 -1
  22. package/dist/dataStoreContexts.js.map +1 -1
  23. package/dist/dataStoreRegistry.js +2 -2
  24. package/dist/dataStoreRegistry.js.map +1 -1
  25. package/dist/dataStores.d.ts.map +1 -1
  26. package/dist/dataStores.js +4 -5
  27. package/dist/dataStores.js.map +1 -1
  28. package/dist/error.d.ts +14 -0
  29. package/dist/error.d.ts.map +1 -0
  30. package/dist/error.js +21 -0
  31. package/dist/error.js.map +1 -0
  32. package/dist/gc/garbageCollection.d.ts +1 -1
  33. package/dist/gc/garbageCollection.d.ts.map +1 -1
  34. package/dist/gc/garbageCollection.js +23 -5
  35. package/dist/gc/garbageCollection.js.map +1 -1
  36. package/dist/gc/gcConfigs.d.ts.map +1 -1
  37. package/dist/gc/gcConfigs.js +5 -3
  38. package/dist/gc/gcConfigs.js.map +1 -1
  39. package/dist/gc/gcDefinitions.d.ts +2 -0
  40. package/dist/gc/gcDefinitions.d.ts.map +1 -1
  41. package/dist/gc/gcDefinitions.js.map +1 -1
  42. package/dist/gc/gcTelemetry.d.ts.map +1 -1
  43. package/dist/gc/gcTelemetry.js +2 -0
  44. package/dist/gc/gcTelemetry.js.map +1 -1
  45. package/dist/id-compressor/appendOnlySortedMap.d.ts +8 -30
  46. package/dist/id-compressor/appendOnlySortedMap.d.ts.map +1 -1
  47. package/dist/id-compressor/appendOnlySortedMap.js +25 -67
  48. package/dist/id-compressor/appendOnlySortedMap.js.map +1 -1
  49. package/dist/id-compressor/finalSpace.d.ts +29 -0
  50. package/dist/id-compressor/finalSpace.d.ts.map +1 -0
  51. package/dist/id-compressor/finalSpace.js +62 -0
  52. package/dist/id-compressor/finalSpace.js.map +1 -0
  53. package/dist/id-compressor/idCompressor.d.ts +25 -250
  54. package/dist/id-compressor/idCompressor.d.ts.map +1 -1
  55. package/dist/id-compressor/idCompressor.js +385 -1149
  56. package/dist/id-compressor/idCompressor.js.map +1 -1
  57. package/dist/id-compressor/identifiers.d.ts +32 -0
  58. package/dist/id-compressor/identifiers.d.ts.map +1 -0
  59. package/dist/id-compressor/identifiers.js +15 -0
  60. package/dist/id-compressor/identifiers.js.map +1 -0
  61. package/dist/id-compressor/index.d.ts +5 -6
  62. package/dist/id-compressor/index.d.ts.map +1 -1
  63. package/dist/id-compressor/index.js +20 -26
  64. package/dist/id-compressor/index.js.map +1 -1
  65. package/dist/id-compressor/persistanceUtilities.d.ts +22 -0
  66. package/dist/id-compressor/persistanceUtilities.d.ts.map +1 -0
  67. package/dist/id-compressor/persistanceUtilities.js +43 -0
  68. package/dist/id-compressor/persistanceUtilities.js.map +1 -0
  69. package/dist/id-compressor/sessionSpaceNormalizer.d.ts +46 -0
  70. package/dist/id-compressor/sessionSpaceNormalizer.d.ts.map +1 -0
  71. package/dist/id-compressor/sessionSpaceNormalizer.js +80 -0
  72. package/dist/id-compressor/sessionSpaceNormalizer.js.map +1 -0
  73. package/dist/id-compressor/sessions.d.ts +115 -0
  74. package/dist/id-compressor/sessions.d.ts.map +1 -0
  75. package/dist/id-compressor/sessions.js +305 -0
  76. package/dist/id-compressor/sessions.js.map +1 -0
  77. package/dist/id-compressor/utilities.d.ts +49 -0
  78. package/dist/id-compressor/utilities.d.ts.map +1 -0
  79. package/dist/id-compressor/utilities.js +166 -0
  80. package/dist/id-compressor/utilities.js.map +1 -0
  81. package/dist/index.d.ts +3 -3
  82. package/dist/index.d.ts.map +1 -1
  83. package/dist/index.js +6 -4
  84. package/dist/index.js.map +1 -1
  85. package/dist/opLifecycle/opCompressor.d.ts.map +1 -1
  86. package/dist/opLifecycle/opCompressor.js +1 -2
  87. package/dist/opLifecycle/opCompressor.js.map +1 -1
  88. package/dist/opLifecycle/opSplitter.d.ts.map +1 -1
  89. package/dist/opLifecycle/opSplitter.js +2 -3
  90. package/dist/opLifecycle/opSplitter.js.map +1 -1
  91. package/dist/opLifecycle/outbox.d.ts +1 -0
  92. package/dist/opLifecycle/outbox.d.ts.map +1 -1
  93. package/dist/opLifecycle/outbox.js +10 -11
  94. package/dist/opLifecycle/outbox.js.map +1 -1
  95. package/dist/opLifecycle/remoteMessageProcessor.d.ts.map +1 -1
  96. package/dist/opLifecycle/remoteMessageProcessor.js +11 -5
  97. package/dist/opLifecycle/remoteMessageProcessor.js.map +1 -1
  98. package/dist/packageVersion.d.ts +1 -1
  99. package/dist/packageVersion.js +1 -1
  100. package/dist/packageVersion.js.map +1 -1
  101. package/dist/pendingStateManager.d.ts +12 -5
  102. package/dist/pendingStateManager.d.ts.map +1 -1
  103. package/dist/pendingStateManager.js +24 -10
  104. package/dist/pendingStateManager.js.map +1 -1
  105. package/dist/scheduleManager.d.ts.map +1 -1
  106. package/dist/scheduleManager.js +4 -5
  107. package/dist/scheduleManager.js.map +1 -1
  108. package/dist/summary/index.d.ts +2 -2
  109. package/dist/summary/index.d.ts.map +1 -1
  110. package/dist/summary/index.js +2 -1
  111. package/dist/summary/index.js.map +1 -1
  112. package/dist/summary/orderedClientElection.d.ts +1 -2
  113. package/dist/summary/orderedClientElection.d.ts.map +1 -1
  114. package/dist/summary/orderedClientElection.js +2 -3
  115. package/dist/summary/orderedClientElection.js.map +1 -1
  116. package/dist/summary/runningSummarizer.d.ts +27 -4
  117. package/dist/summary/runningSummarizer.d.ts.map +1 -1
  118. package/dist/summary/runningSummarizer.js +237 -66
  119. package/dist/summary/runningSummarizer.js.map +1 -1
  120. package/dist/summary/summarizer.d.ts +6 -5
  121. package/dist/summary/summarizer.d.ts.map +1 -1
  122. package/dist/summary/summarizer.js +70 -67
  123. package/dist/summary/summarizer.js.map +1 -1
  124. package/dist/summary/summarizerClientElection.d.ts +1 -1
  125. package/dist/summary/summarizerClientElection.d.ts.map +1 -1
  126. package/dist/summary/summarizerClientElection.js.map +1 -1
  127. package/dist/summary/summarizerTypes.d.ts +38 -25
  128. package/dist/summary/summarizerTypes.d.ts.map +1 -1
  129. package/dist/summary/summarizerTypes.js.map +1 -1
  130. package/dist/summary/summaryCollection.d.ts +1 -2
  131. package/dist/summary/summaryCollection.d.ts.map +1 -1
  132. package/dist/summary/summaryCollection.js.map +1 -1
  133. package/dist/summary/summaryGenerator.d.ts +9 -3
  134. package/dist/summary/summaryGenerator.d.ts.map +1 -1
  135. package/dist/summary/summaryGenerator.js +42 -38
  136. package/dist/summary/summaryGenerator.js.map +1 -1
  137. package/dist/summary/summaryManager.d.ts +7 -6
  138. package/dist/summary/summaryManager.d.ts.map +1 -1
  139. package/dist/summary/summaryManager.js +22 -15
  140. package/dist/summary/summaryManager.js.map +1 -1
  141. package/lib/batchTracker.d.ts +1 -1
  142. package/lib/batchTracker.js +1 -1
  143. package/lib/batchTracker.js.map +1 -1
  144. package/lib/blobManager.d.ts +4 -20
  145. package/lib/blobManager.d.ts.map +1 -1
  146. package/lib/blobManager.js +46 -124
  147. package/lib/blobManager.js.map +1 -1
  148. package/lib/containerRuntime.d.ts +82 -14
  149. package/lib/containerRuntime.d.ts.map +1 -1
  150. package/lib/containerRuntime.js +223 -123
  151. package/lib/containerRuntime.js.map +1 -1
  152. package/lib/dataStore.d.ts.map +1 -1
  153. package/lib/dataStore.js +1 -2
  154. package/lib/dataStore.js.map +1 -1
  155. package/lib/dataStoreContext.d.ts.map +1 -1
  156. package/lib/dataStoreContext.js +1 -2
  157. package/lib/dataStoreContext.js.map +1 -1
  158. package/lib/dataStoreContexts.d.ts +1 -2
  159. package/lib/dataStoreContexts.d.ts.map +1 -1
  160. package/lib/dataStoreContexts.js.map +1 -1
  161. package/lib/dataStoreRegistry.js +1 -1
  162. package/lib/dataStoreRegistry.js.map +1 -1
  163. package/lib/dataStores.d.ts.map +1 -1
  164. package/lib/dataStores.js +1 -2
  165. package/lib/dataStores.js.map +1 -1
  166. package/lib/error.d.ts +14 -0
  167. package/lib/error.d.ts.map +1 -0
  168. package/lib/error.js +17 -0
  169. package/lib/error.js.map +1 -0
  170. package/lib/gc/garbageCollection.d.ts +1 -1
  171. package/lib/gc/garbageCollection.d.ts.map +1 -1
  172. package/lib/gc/garbageCollection.js +22 -4
  173. package/lib/gc/garbageCollection.js.map +1 -1
  174. package/lib/gc/gcConfigs.d.ts.map +1 -1
  175. package/lib/gc/gcConfigs.js +3 -1
  176. package/lib/gc/gcConfigs.js.map +1 -1
  177. package/lib/gc/gcDefinitions.d.ts +2 -0
  178. package/lib/gc/gcDefinitions.d.ts.map +1 -1
  179. package/lib/gc/gcDefinitions.js.map +1 -1
  180. package/lib/gc/gcTelemetry.d.ts.map +1 -1
  181. package/lib/gc/gcTelemetry.js +2 -0
  182. package/lib/gc/gcTelemetry.js.map +1 -1
  183. package/lib/id-compressor/appendOnlySortedMap.d.ts +8 -30
  184. package/lib/id-compressor/appendOnlySortedMap.d.ts.map +1 -1
  185. package/lib/id-compressor/appendOnlySortedMap.js +24 -65
  186. package/lib/id-compressor/appendOnlySortedMap.js.map +1 -1
  187. package/lib/id-compressor/finalSpace.d.ts +29 -0
  188. package/lib/id-compressor/finalSpace.d.ts.map +1 -0
  189. package/lib/id-compressor/finalSpace.js +58 -0
  190. package/lib/id-compressor/finalSpace.js.map +1 -0
  191. package/lib/id-compressor/idCompressor.d.ts +25 -250
  192. package/lib/id-compressor/idCompressor.d.ts.map +1 -1
  193. package/lib/id-compressor/idCompressor.js +381 -1139
  194. package/lib/id-compressor/idCompressor.js.map +1 -1
  195. package/lib/id-compressor/identifiers.d.ts +32 -0
  196. package/lib/id-compressor/identifiers.d.ts.map +1 -0
  197. package/lib/id-compressor/identifiers.js +11 -0
  198. package/lib/id-compressor/identifiers.js.map +1 -0
  199. package/lib/id-compressor/index.d.ts +5 -6
  200. package/lib/id-compressor/index.d.ts.map +1 -1
  201. package/lib/id-compressor/index.js +5 -6
  202. package/lib/id-compressor/index.js.map +1 -1
  203. package/lib/id-compressor/persistanceUtilities.d.ts +22 -0
  204. package/lib/id-compressor/persistanceUtilities.d.ts.map +1 -0
  205. package/lib/id-compressor/persistanceUtilities.js +34 -0
  206. package/lib/id-compressor/persistanceUtilities.js.map +1 -0
  207. package/lib/id-compressor/sessionSpaceNormalizer.d.ts +46 -0
  208. package/lib/id-compressor/sessionSpaceNormalizer.d.ts.map +1 -0
  209. package/lib/id-compressor/sessionSpaceNormalizer.js +76 -0
  210. package/lib/id-compressor/sessionSpaceNormalizer.js.map +1 -0
  211. package/lib/id-compressor/sessions.d.ts +115 -0
  212. package/lib/id-compressor/sessions.d.ts.map +1 -0
  213. package/lib/id-compressor/sessions.js +290 -0
  214. package/lib/id-compressor/sessions.js.map +1 -0
  215. package/lib/id-compressor/utilities.d.ts +49 -0
  216. package/lib/id-compressor/utilities.d.ts.map +1 -0
  217. package/lib/id-compressor/utilities.js +148 -0
  218. package/lib/id-compressor/utilities.js.map +1 -0
  219. package/lib/index.d.ts +3 -3
  220. package/lib/index.d.ts.map +1 -1
  221. package/lib/index.js +2 -2
  222. package/lib/index.js.map +1 -1
  223. package/lib/opLifecycle/opCompressor.d.ts.map +1 -1
  224. package/lib/opLifecycle/opCompressor.js +1 -2
  225. package/lib/opLifecycle/opCompressor.js.map +1 -1
  226. package/lib/opLifecycle/opSplitter.d.ts.map +1 -1
  227. package/lib/opLifecycle/opSplitter.js +1 -2
  228. package/lib/opLifecycle/opSplitter.js.map +1 -1
  229. package/lib/opLifecycle/outbox.d.ts +1 -0
  230. package/lib/opLifecycle/outbox.d.ts.map +1 -1
  231. package/lib/opLifecycle/outbox.js +6 -7
  232. package/lib/opLifecycle/outbox.js.map +1 -1
  233. package/lib/opLifecycle/remoteMessageProcessor.d.ts.map +1 -1
  234. package/lib/opLifecycle/remoteMessageProcessor.js +12 -6
  235. package/lib/opLifecycle/remoteMessageProcessor.js.map +1 -1
  236. package/lib/packageVersion.d.ts +1 -1
  237. package/lib/packageVersion.js +1 -1
  238. package/lib/packageVersion.js.map +1 -1
  239. package/lib/pendingStateManager.d.ts +12 -5
  240. package/lib/pendingStateManager.d.ts.map +1 -1
  241. package/lib/pendingStateManager.js +21 -7
  242. package/lib/pendingStateManager.js.map +1 -1
  243. package/lib/scheduleManager.d.ts.map +1 -1
  244. package/lib/scheduleManager.js +1 -2
  245. package/lib/scheduleManager.js.map +1 -1
  246. package/lib/summary/index.d.ts +2 -2
  247. package/lib/summary/index.d.ts.map +1 -1
  248. package/lib/summary/index.js +1 -1
  249. package/lib/summary/index.js.map +1 -1
  250. package/lib/summary/orderedClientElection.d.ts +1 -2
  251. package/lib/summary/orderedClientElection.d.ts.map +1 -1
  252. package/lib/summary/orderedClientElection.js +1 -2
  253. package/lib/summary/orderedClientElection.js.map +1 -1
  254. package/lib/summary/runningSummarizer.d.ts +27 -4
  255. package/lib/summary/runningSummarizer.d.ts.map +1 -1
  256. package/lib/summary/runningSummarizer.js +237 -66
  257. package/lib/summary/runningSummarizer.js.map +1 -1
  258. package/lib/summary/summarizer.d.ts +6 -5
  259. package/lib/summary/summarizer.d.ts.map +1 -1
  260. package/lib/summary/summarizer.js +68 -65
  261. package/lib/summary/summarizer.js.map +1 -1
  262. package/lib/summary/summarizerClientElection.d.ts +1 -1
  263. package/lib/summary/summarizerClientElection.d.ts.map +1 -1
  264. package/lib/summary/summarizerClientElection.js.map +1 -1
  265. package/lib/summary/summarizerTypes.d.ts +38 -25
  266. package/lib/summary/summarizerTypes.d.ts.map +1 -1
  267. package/lib/summary/summarizerTypes.js.map +1 -1
  268. package/lib/summary/summaryCollection.d.ts +1 -2
  269. package/lib/summary/summaryCollection.d.ts.map +1 -1
  270. package/lib/summary/summaryCollection.js.map +1 -1
  271. package/lib/summary/summaryGenerator.d.ts +9 -3
  272. package/lib/summary/summaryGenerator.d.ts.map +1 -1
  273. package/lib/summary/summaryGenerator.js +43 -39
  274. package/lib/summary/summaryGenerator.js.map +1 -1
  275. package/lib/summary/summaryManager.d.ts +7 -6
  276. package/lib/summary/summaryManager.d.ts.map +1 -1
  277. package/lib/summary/summaryManager.js +23 -16
  278. package/lib/summary/summaryManager.js.map +1 -1
  279. package/package.json +27 -24
  280. package/src/batchTracker.ts +1 -1
  281. package/src/blobManager.ts +57 -146
  282. package/src/containerRuntime.ts +331 -158
  283. package/src/dataStore.ts +1 -2
  284. package/src/dataStoreContext.ts +3 -6
  285. package/src/dataStoreContexts.ts +1 -2
  286. package/src/dataStoreRegistry.ts +1 -1
  287. package/src/dataStores.ts +3 -5
  288. package/src/error.ts +18 -0
  289. package/src/gc/garbageCollection.ts +38 -5
  290. package/src/gc/gcConfigs.ts +4 -2
  291. package/src/gc/gcDefinitions.ts +2 -0
  292. package/src/gc/gcTelemetry.ts +2 -0
  293. package/src/id-compressor/appendOnlySortedMap.ts +25 -86
  294. package/src/id-compressor/finalSpace.ts +67 -0
  295. package/src/id-compressor/idCompressor.ts +455 -1681
  296. package/src/id-compressor/identifiers.ts +42 -0
  297. package/src/id-compressor/index.ts +11 -20
  298. package/src/id-compressor/persistanceUtilities.ts +58 -0
  299. package/src/id-compressor/sessionSpaceNormalizer.ts +83 -0
  300. package/src/id-compressor/sessions.ts +405 -0
  301. package/src/id-compressor/utilities.ts +187 -0
  302. package/src/index.ts +7 -1
  303. package/src/opLifecycle/opCompressor.ts +1 -2
  304. package/src/opLifecycle/opSplitter.ts +4 -4
  305. package/src/opLifecycle/outbox.ts +13 -10
  306. package/src/opLifecycle/remoteMessageProcessor.ts +19 -6
  307. package/src/packageVersion.ts +1 -1
  308. package/src/pendingStateManager.ts +49 -27
  309. package/src/scheduleManager.ts +5 -4
  310. package/src/summary/index.ts +3 -1
  311. package/src/summary/orderedClientElection.ts +6 -4
  312. package/src/summary/runningSummarizer.ts +276 -95
  313. package/src/summary/summarizer.ts +22 -12
  314. package/src/summary/summarizerClientElection.ts +1 -1
  315. package/src/summary/summarizerTypes.ts +40 -25
  316. package/src/summary/summaryCollection.ts +1 -2
  317. package/src/summary/summaryGenerator.ts +49 -52
  318. package/src/summary/summaryManager.ts +33 -11
  319. package/dist/id-compressor/idRange.d.ts +0 -11
  320. package/dist/id-compressor/idRange.d.ts.map +0 -1
  321. package/dist/id-compressor/idRange.js +0 -29
  322. package/dist/id-compressor/idRange.js.map +0 -1
  323. package/dist/id-compressor/numericUuid.d.ts +0 -59
  324. package/dist/id-compressor/numericUuid.d.ts.map +0 -1
  325. package/dist/id-compressor/numericUuid.js +0 -325
  326. package/dist/id-compressor/numericUuid.js.map +0 -1
  327. package/dist/id-compressor/sessionIdNormalizer.d.ts +0 -138
  328. package/dist/id-compressor/sessionIdNormalizer.d.ts.map +0 -1
  329. package/dist/id-compressor/sessionIdNormalizer.js +0 -483
  330. package/dist/id-compressor/sessionIdNormalizer.js.map +0 -1
  331. package/dist/id-compressor/utils.d.ts +0 -57
  332. package/dist/id-compressor/utils.d.ts.map +0 -1
  333. package/dist/id-compressor/utils.js +0 -90
  334. package/dist/id-compressor/utils.js.map +0 -1
  335. package/dist/id-compressor/uuidUtilities.d.ts +0 -28
  336. package/dist/id-compressor/uuidUtilities.d.ts.map +0 -1
  337. package/dist/id-compressor/uuidUtilities.js +0 -104
  338. package/dist/id-compressor/uuidUtilities.js.map +0 -1
  339. package/lib/id-compressor/idRange.d.ts +0 -11
  340. package/lib/id-compressor/idRange.d.ts.map +0 -1
  341. package/lib/id-compressor/idRange.js +0 -25
  342. package/lib/id-compressor/idRange.js.map +0 -1
  343. package/lib/id-compressor/numericUuid.d.ts +0 -59
  344. package/lib/id-compressor/numericUuid.d.ts.map +0 -1
  345. package/lib/id-compressor/numericUuid.js +0 -315
  346. package/lib/id-compressor/numericUuid.js.map +0 -1
  347. package/lib/id-compressor/sessionIdNormalizer.d.ts +0 -138
  348. package/lib/id-compressor/sessionIdNormalizer.d.ts.map +0 -1
  349. package/lib/id-compressor/sessionIdNormalizer.js +0 -479
  350. package/lib/id-compressor/sessionIdNormalizer.js.map +0 -1
  351. package/lib/id-compressor/utils.d.ts +0 -57
  352. package/lib/id-compressor/utils.d.ts.map +0 -1
  353. package/lib/id-compressor/utils.js +0 -79
  354. package/lib/id-compressor/utils.js.map +0 -1
  355. package/lib/id-compressor/uuidUtilities.d.ts +0 -28
  356. package/lib/id-compressor/uuidUtilities.d.ts.map +0 -1
  357. package/lib/id-compressor/uuidUtilities.js +0 -96
  358. package/lib/id-compressor/uuidUtilities.js.map +0 -1
  359. package/src/id-compressor/idRange.ts +0 -35
  360. package/src/id-compressor/numericUuid.ts +0 -383
  361. package/src/id-compressor/sessionIdNormalizer.ts +0 -609
  362. package/src/id-compressor/utils.ts +0 -114
  363. package/src/id-compressor/uuidUtilities.ts +0 -120
@@ -27,23 +27,22 @@ import {
27
27
  IContainerRuntime,
28
28
  IContainerRuntimeEvents,
29
29
  } from "@fluidframework/container-runtime-definitions";
30
- import {
31
- assert,
32
- delay,
33
- Trace,
34
- TypedEventEmitter,
35
- unreachableCase,
36
- } from "@fluidframework/common-utils";
30
+ import { assert, delay, Trace, TypedEventEmitter } from "@fluidframework/common-utils";
37
31
  import { LazyPromise } from "@fluidframework/core-utils";
38
32
  import {
39
33
  createChildLogger,
34
+ createChildMonitoringContext,
35
+ DataCorruptionError,
36
+ DataProcessingError,
37
+ GenericError,
40
38
  raiseConnectedEvent,
41
39
  PerformanceEvent,
40
+ // eslint-disable-next-line import/no-deprecated
42
41
  TaggedLoggerAdapter,
43
42
  MonitoringContext,
44
43
  wrapError,
45
44
  ITelemetryLoggerExt,
46
- createChildMonitoringContext,
45
+ UsageError,
47
46
  } from "@fluidframework/telemetry-utils";
48
47
  import {
49
48
  DriverHeader,
@@ -52,12 +51,6 @@ import {
52
51
  ISummaryContext,
53
52
  } from "@fluidframework/driver-definitions";
54
53
  import { readAndParse } from "@fluidframework/driver-utils";
55
- import {
56
- DataCorruptionError,
57
- DataProcessingError,
58
- GenericError,
59
- UsageError,
60
- } from "@fluidframework/container-utils";
61
54
  import {
62
55
  IClientDetails,
63
56
  IDocumentMessage,
@@ -157,6 +150,11 @@ import {
157
150
  RunWhileConnectedCoordinator,
158
151
  IGenerateSummaryTreeResult,
159
152
  RetriableSummaryError,
153
+ IOnDemandSummarizeOptions,
154
+ ISummarizeResults,
155
+ IEnqueueSummarizeOptions,
156
+ EnqueueSummarizeResult,
157
+ ISummarizerEvents,
160
158
  } from "./summary";
161
159
  import { formExponentialFn, Throttler } from "./throttler";
162
160
  import {
@@ -214,11 +212,64 @@ export enum ContainerMessageType {
214
212
  IdAllocation = "idAllocation",
215
213
  }
216
214
 
215
+ /**
216
+ * How should an older client handle an unrecognized remote op type?
217
+ *
218
+ * @internal
219
+ */
220
+ export type CompatModeBehavior =
221
+ /** Ignore the op. It won't be persisted if this client summarizes */
222
+ | "Ignore"
223
+ /** Fail processing immediately. (The container will close) */
224
+ | "FailToProcess";
225
+
226
+ /**
227
+ * All the info an older client would need to know how to handle an unrecognized remote op type
228
+ *
229
+ * @internal
230
+ */
231
+ export interface IContainerRuntimeMessageCompatDetails {
232
+ /** How should an older client handle an unrecognized remote op type? */
233
+ behavior: CompatModeBehavior;
234
+ }
235
+
236
+ /**
237
+ * Utility to implement compat behaviors given an unknown message type
238
+ * The parameters are typed to support compile-time enforcement of handling all known types/behaviors
239
+ *
240
+ * @param _unknownContainerRuntimeMessageType - Typed as never, to ensure all known types have been
241
+ * handled before calling this function (e.g. in a switch statement).
242
+ * @param compatBehavior - Typed redundantly with CompatModeBehavior to ensure handling is added when updating that type
243
+ */
244
+ function compatBehaviorAllowsMessageType(
245
+ _unknownContainerRuntimeMessageType: never,
246
+ compatBehavior: "Ignore" | "FailToProcess" | undefined,
247
+ ): boolean {
248
+ // undefined defaults to same behavior as "FailToProcess"
249
+ return compatBehavior === "Ignore";
250
+ }
251
+
252
+ /**
253
+ * The unpacked runtime message / details to be handled or dispatched by the ContainerRuntime
254
+ *
255
+ * IMPORTANT: when creating one to be serialized, set the properties in the order they appear here.
256
+ * This way stringified values can be compared.
257
+ */
217
258
  export interface ContainerRuntimeMessage {
218
- contents: any;
259
+ /** Type of the op, within the ContainerRuntime's domain */
219
260
  type: ContainerMessageType;
261
+ /** Domain-specific contents, interpreted according to the type */
262
+ contents: any;
263
+ /** Info describing how to handle this op in case the type is unrecognized (default: fail to process) */
264
+ compatDetails?: IContainerRuntimeMessageCompatDetails;
220
265
  }
221
266
 
267
+ /**
268
+ * An unpacked ISequencedDocumentMessage with the inner ContainerRuntimeMessage type/contents/etc
269
+ * promoted up to the outer object
270
+ */
271
+ export type SequencedContainerRuntimeMessage = ISequencedDocumentMessage & ContainerRuntimeMessage;
272
+
222
273
  export interface ISummaryBaseConfiguration {
223
274
  /**
224
275
  * Delay before first attempt to spawn summarizing container.
@@ -457,9 +508,13 @@ export enum RuntimeHeaders {
457
508
 
458
509
  /** True if a tombstoned object should be returned without erroring */
459
510
  export const AllowTombstoneRequestHeaderKey = "allowTombstone"; // Belongs in the enum above, but avoiding the breaking change
511
+ /** [IRRELEVANT IF throwOnInactiveLoad OPTION NOT SET] True if an inactive object should be returned without erroring */
512
+ export const AllowInactiveRequestHeaderKey = "allowInactive"; // Belongs in the enum above, but avoiding the breaking change
460
513
 
461
514
  /** Tombstone error responses will have this header set to true */
462
515
  export const TombstoneResponseHeaderKey = "isTombstoned";
516
+ /** Inactive error responses will have this header set to true */
517
+ export const InactiveResponseHeaderKey = "isInactive";
463
518
 
464
519
  /**
465
520
  * The full set of parsed header data that may be found on Runtime requests
@@ -500,7 +555,7 @@ interface OldContainerContextWithLogger extends Omit<IContainerContext, "taggedL
500
555
  * instantiated runtime in a new instance of the container, so it can load to the
501
556
  * same state
502
557
  */
503
- interface IPendingRuntimeState {
558
+ export interface IPendingRuntimeState {
504
559
  /**
505
560
  * Pending ops from PendingStateManager
506
561
  */
@@ -605,7 +660,7 @@ export const makeLegacySendBatchFn =
605
660
  * It will define the store level mappings.
606
661
  */
607
662
  export class ContainerRuntime
608
- extends TypedEventEmitter<IContainerRuntimeEvents>
663
+ extends TypedEventEmitter<IContainerRuntimeEvents & ISummarizerEvents>
609
664
  implements IContainerRuntime, IRuntime, ISummarizerRuntime, ISummarizerInternalsProvider
610
665
  {
611
666
  /**
@@ -665,16 +720,30 @@ export class ContainerRuntime
665
720
  * - initializeEntryPoint - Promise that resolves to an object which will act as entryPoint for the Container.
666
721
  * This object should provide all the functionality that the Container is expected to provide to the loader layer.
667
722
  */
668
- public static async loadRuntime(params: {
669
- context: IContainerContext;
670
- registryEntries: NamedFluidDataStoreRegistryEntries;
671
- existing: boolean;
672
- requestHandler?: (request: IRequest, runtime: IContainerRuntime) => Promise<IResponse>;
673
- runtimeOptions?: IContainerRuntimeOptions;
674
- containerScope?: FluidObject;
675
- containerRuntimeCtor?: typeof ContainerRuntime;
676
- initializeEntryPoint?: (containerRuntime: IContainerRuntime) => Promise<FluidObject>;
677
- }): Promise<ContainerRuntime> {
723
+ public static async loadRuntime(
724
+ params: {
725
+ context: IContainerContext;
726
+ registryEntries: NamedFluidDataStoreRegistryEntries;
727
+ existing: boolean;
728
+ runtimeOptions?: IContainerRuntimeOptions;
729
+ containerScope?: FluidObject;
730
+ containerRuntimeCtor?: typeof ContainerRuntime;
731
+ } & (
732
+ | {
733
+ requestHandler?: (
734
+ request: IRequest,
735
+ runtime: IContainerRuntime,
736
+ ) => Promise<IResponse>;
737
+ initializeEntryPoint?: undefined;
738
+ }
739
+ | {
740
+ requestHandler?: undefined;
741
+ initializeEntryPoint: (
742
+ containerRuntime: IContainerRuntime,
743
+ ) => Promise<FluidObject>;
744
+ }
745
+ ),
746
+ ): Promise<ContainerRuntime> {
678
747
  const {
679
748
  context,
680
749
  registryEntries,
@@ -683,14 +752,25 @@ export class ContainerRuntime
683
752
  runtimeOptions = {},
684
753
  containerScope = {},
685
754
  containerRuntimeCtor = ContainerRuntime,
686
- initializeEntryPoint,
687
755
  } = params;
688
756
 
757
+ const initializeEntryPoint =
758
+ params.initializeEntryPoint ??
759
+ (async (containerRuntime: IContainerRuntime) => ({
760
+ get IFluidRouter() {
761
+ return this;
762
+ },
763
+ async request(req) {
764
+ return containerRuntime.request(req);
765
+ },
766
+ }));
767
+
689
768
  // If taggedLogger exists, use it. Otherwise, wrap the vanilla logger:
690
769
  // back-compat: Remove the TaggedLoggerAdapter fallback once all the host are using loader > 0.45
691
770
  const backCompatContext: IContainerContext | OldContainerContextWithLogger = context;
692
771
  const passLogger =
693
772
  backCompatContext.taggedLogger ??
773
+ // eslint-disable-next-line import/no-deprecated
694
774
  new TaggedLoggerAdapter((backCompatContext as OldContainerContextWithLogger).logger);
695
775
  const logger = createChildLogger({
696
776
  logger: passLogger,
@@ -785,7 +865,7 @@ export class ContainerRuntime
785
865
  idCompressor =
786
866
  serializedIdCompressor !== undefined
787
867
  ? IdCompressor.deserialize(serializedIdCompressor, createSessionId())
788
- : new IdCompressor(createSessionId(), logger);
868
+ : IdCompressor.create(logger);
789
869
  }
790
870
 
791
871
  const runtime = new containerRuntimeCtor(
@@ -818,6 +898,7 @@ export class ContainerRuntime
818
898
  initializeEntryPoint,
819
899
  );
820
900
 
901
+ await runtime.blobManager.processStashedChanges();
821
902
  // It's possible to have ops with a reference sequence number of 0. Op sequence numbers start
822
903
  // at 1, so we won't see a replayed saved op with a sequence number of 0.
823
904
  await runtime.pendingStateManager.applyStashedOpsAt(0);
@@ -849,6 +930,7 @@ export class ContainerRuntime
849
930
  localOpMetadata: unknown,
850
931
  opMetadata: Record<string, unknown> | undefined,
851
932
  ) => this.reSubmitCore({ type, contents }, localOpMetadata, opMetadata);
933
+ // Note: compatDetails is not included in this deprecated API
852
934
  }
853
935
 
854
936
  private readonly submitFn: (
@@ -994,7 +1076,7 @@ export class ContainerRuntime
994
1076
  private readonly validateSummaryBeforeUpload: boolean;
995
1077
 
996
1078
  private readonly defaultTelemetrySignalSampleCount = 100;
997
- private _perfSignalData: IPerfSignalReport = {
1079
+ private readonly _perfSignalData: IPerfSignalReport = {
998
1080
  signalsLost: 0,
999
1081
  signalSequenceNumber: 0,
1000
1082
  signalTimestamp: 0,
@@ -1478,8 +1560,7 @@ export class ContainerRuntime
1478
1560
  this.summaryCollection = new SummaryCollection(this.deltaManager, this.logger);
1479
1561
 
1480
1562
  this.dirtyContainer =
1481
- this.attachState !== AttachState.Attached ||
1482
- this.pendingStateManager.hasPendingMessages();
1563
+ this.attachState !== AttachState.Attached || this.hasPendingMessages();
1483
1564
  context.updateDirtyContainerState(this.dirtyContainer);
1484
1565
 
1485
1566
  if (this.summariesDisabled) {
@@ -1564,6 +1645,9 @@ export class ContainerRuntime
1564
1645
  },
1565
1646
  this.heuristicsDisabled,
1566
1647
  );
1648
+ this.summaryManager.on("summarize", (eventProps) => {
1649
+ this.emit("summarize", eventProps);
1650
+ });
1567
1651
  this.summaryManager.start();
1568
1652
  }
1569
1653
  }
@@ -1736,7 +1820,7 @@ export class ContainerRuntime
1736
1820
  subRequest.url.startsWith("/"),
1737
1821
  0x126 /* "Expected createSubRequest url to include a leading slash" */,
1738
1822
  );
1739
- return dataStore.IFluidRouter.request(subRequest);
1823
+ return dataStore.request(subRequest);
1740
1824
  }
1741
1825
 
1742
1826
  return create404Response(request);
@@ -1784,6 +1868,7 @@ export class ContainerRuntime
1784
1868
  dataStoreContext.packagePath,
1785
1869
  request?.headers,
1786
1870
  );
1871
+
1787
1872
  return dataStoreChannel;
1788
1873
  }
1789
1874
 
@@ -1878,7 +1963,7 @@ export class ContainerRuntime
1878
1963
  this.mc.logger.sendTelemetryEvent({
1879
1964
  eventName: "ReconnectsWithNoProgress",
1880
1965
  attempts: this.consecutiveReconnects,
1881
- pendingMessages: this.pendingStateManager.pendingMessagesCount,
1966
+ pendingMessages: this.pendingMessagesCount,
1882
1967
  });
1883
1968
  }
1884
1969
 
@@ -1947,14 +2032,15 @@ export class ContainerRuntime
1947
2032
  */
1948
2033
  private parseOpContent(serializedContent?: string): ContainerRuntimeMessage {
1949
2034
  assert(serializedContent !== undefined, 0x6d5 /* content must be defined */);
1950
- const { type, contents } = JSON.parse(serializedContent);
2035
+ const { type, contents, compatDetails }: ContainerRuntimeMessage =
2036
+ JSON.parse(serializedContent);
1951
2037
  assert(type !== undefined, 0x6d6 /* incorrect op content format */);
1952
- return { type, contents };
2038
+ return { type, contents, compatDetails };
1953
2039
  }
1954
2040
 
1955
2041
  private async applyStashedOp(op: string): Promise<unknown> {
1956
2042
  // Need to parse from string for back-compat
1957
- const { type, contents } = this.parseOpContent(op);
2043
+ const { type, contents, compatDetails } = this.parseOpContent(op);
1958
2044
  switch (type) {
1959
2045
  case ContainerMessageType.FluidDataStoreOp:
1960
2046
  return this.dataStores.applyStashedOp(contents as IEnvelope);
@@ -1973,8 +2059,27 @@ export class ContainerRuntime
1973
2059
  throw new Error("chunkedOp not expected here");
1974
2060
  case ContainerMessageType.Rejoin:
1975
2061
  throw new Error("rejoin not expected here");
1976
- default:
1977
- unreachableCase(type, `Unknown ContainerMessageType: ${type}`);
2062
+ default: {
2063
+ // This should be extremely rare for stashed ops.
2064
+ // It would require a newer runtime stashing ops and then an older one applying them,
2065
+ // e.g. if an app rolled back its container version
2066
+ const compatBehavior = compatDetails?.behavior;
2067
+ if (!compatBehaviorAllowsMessageType(type, compatBehavior)) {
2068
+ const error = DataProcessingError.create(
2069
+ "Stashed runtime message of unknown type",
2070
+ "applyStashedOp",
2071
+ undefined /* sequencedMessage */,
2072
+ {
2073
+ messageDetails: JSON.stringify({
2074
+ type,
2075
+ compatBehavior,
2076
+ }),
2077
+ },
2078
+ );
2079
+ this.closeFn(error);
2080
+ throw error;
2081
+ }
2082
+ }
1978
2083
  }
1979
2084
  }
1980
2085
 
@@ -1988,32 +2093,6 @@ export class ContainerRuntime
1988
2093
  return;
1989
2094
  }
1990
2095
 
1991
- // If attachment blobs were added while disconnected, we need to delay
1992
- // propagation of the "connected" event until we have uploaded them to
1993
- // ensure we don't submit ops referencing a blob that has not been uploaded
1994
- // Note that the inner (non-proxy) delta manager is needed here to get the readonly information.
1995
- const connecting =
1996
- connected && !this._connected && !this.innerDeltaManager.readOnlyInfo.readonly;
1997
- if (connecting && this.blobManager.hasPendingOfflineUploads) {
1998
- assert(
1999
- !this.delayConnectClientId,
2000
- 0x392 /* Connect event delay must be canceled before subsequent connect event */,
2001
- );
2002
- assert(!!clientId, 0x393 /* Must have clientId when connecting */);
2003
- this.delayConnectClientId = clientId;
2004
- this.blobManager.onConnected().then(
2005
- () => {
2006
- // make sure we didn't reconnect before the promise resolved
2007
- if (this.delayConnectClientId === clientId && !this.disposed) {
2008
- this.delayConnectClientId = undefined;
2009
- this.setConnectionStateCore(connected, clientId);
2010
- }
2011
- },
2012
- (error) => this.closeFn(error),
2013
- );
2014
- return;
2015
- }
2016
-
2017
2096
  this.setConnectionStateCore(connected, clientId);
2018
2097
  }
2019
2098
 
@@ -2061,7 +2140,7 @@ export class ContainerRuntime
2061
2140
  {
2062
2141
  dataLoss: 1,
2063
2142
  attempts: this.consecutiveReconnects,
2064
- pendingMessages: this.pendingStateManager.pendingMessagesCount,
2143
+ pendingMessages: this.pendingMessagesCount,
2065
2144
  },
2066
2145
  ),
2067
2146
  );
@@ -2086,15 +2165,15 @@ export class ContainerRuntime
2086
2165
  public process(messageArg: ISequencedDocumentMessage, local: boolean) {
2087
2166
  this.verifyNotClosed();
2088
2167
 
2089
- // Whether or not the message is actually a runtime message.
2168
+ // Whether or not the message appears to be a runtime message from an up-to-date client.
2090
2169
  // It may be a legacy runtime message (ie already unpacked and ContainerMessageType)
2091
2170
  // or something different, like a system message.
2092
- const runtimeMessage = messageArg.type === MessageType.Operation;
2171
+ const modernRuntimeMessage = messageArg.type === MessageType.Operation;
2093
2172
 
2094
2173
  // Do shallow copy of message, as the processing flow will modify it.
2095
2174
  const messageCopy = { ...messageArg };
2096
2175
  for (const message of this.remoteMessageProcessor.process(messageCopy)) {
2097
- this.processCore(message, local, runtimeMessage);
2176
+ this.processCore(message, local, modernRuntimeMessage);
2098
2177
  }
2099
2178
  }
2100
2179
 
@@ -2104,12 +2183,12 @@ export class ContainerRuntime
2104
2183
  * Direct the message to the correct subsystem for processing, and implement other side effects
2105
2184
  * @param message - The unpacked message. Likely a ContainerRuntimeMessage, but could also be a system op
2106
2185
  * @param local - Did this client send the op?
2107
- * @param runtimeMessage - Does this appear like a current ContainerRuntimeMessage? If true, certain validation will occur.
2186
+ * @param modernRuntimeMessage - Does this appear like a current ContainerRuntimeMessage?
2108
2187
  */
2109
2188
  private processCore(
2110
- message: ISequencedDocumentMessage,
2189
+ message: ISequencedDocumentMessage | SequencedContainerRuntimeMessage,
2111
2190
  local: boolean,
2112
- runtimeMessage: boolean,
2191
+ modernRuntimeMessage: boolean,
2113
2192
  ) {
2114
2193
  // Surround the actual processing of the operation with messages to the schedule manager indicating
2115
2194
  // the beginning and end. This allows it to emit appropriate events and/or pause the processing of new
@@ -2120,8 +2199,10 @@ export class ContainerRuntime
2120
2199
 
2121
2200
  try {
2122
2201
  let localOpMetadata: unknown;
2123
- if (local && runtimeMessage && message.type !== ContainerMessageType.ChunkedOp) {
2124
- localOpMetadata = this.pendingStateManager.processPendingLocalMessage(message);
2202
+ if (local && modernRuntimeMessage && message.type !== ContainerMessageType.ChunkedOp) {
2203
+ localOpMetadata = this.pendingStateManager.processPendingLocalMessage(
2204
+ message as SequencedContainerRuntimeMessage,
2205
+ );
2125
2206
  }
2126
2207
 
2127
2208
  // If there are no more pending messages after processing a local message,
@@ -2130,51 +2211,14 @@ export class ContainerRuntime
2130
2211
  this.updateDocumentDirtyState(false);
2131
2212
  }
2132
2213
 
2133
- const type = message.type as ContainerMessageType;
2134
- switch (type) {
2135
- case ContainerMessageType.Attach:
2136
- this.dataStores.processAttachMessage(message, local);
2137
- break;
2138
- case ContainerMessageType.Alias:
2139
- this.processAliasMessage(message, localOpMetadata, local);
2140
- break;
2141
- case ContainerMessageType.FluidDataStoreOp:
2142
- this.dataStores.processFluidDataStoreOp(message, local, localOpMetadata);
2143
- break;
2144
- case ContainerMessageType.BlobAttach:
2145
- this.blobManager.processBlobAttachOp(message, local);
2146
- break;
2147
- case ContainerMessageType.IdAllocation:
2148
- assert(
2149
- this.idCompressor !== undefined,
2150
- 0x67c /* IdCompressor should be defined if enabled */,
2151
- );
2152
- this.idCompressor.finalizeCreationRange(message.contents as IdCreationRange);
2153
- break;
2154
- case ContainerMessageType.ChunkedOp:
2155
- case ContainerMessageType.Rejoin:
2156
- break;
2157
- default:
2158
- if (runtimeMessage) {
2159
- const error = DataProcessingError.create(
2160
- // Former assert 0x3ce
2161
- "Runtime message of unknown type",
2162
- "OpProcessing",
2163
- message,
2164
- {
2165
- local,
2166
- type: message.type,
2167
- contentType: typeof message.contents,
2168
- batch: (message.metadata as IBatchMetadata | undefined)?.batch,
2169
- compression: message.compression,
2170
- },
2171
- );
2172
- this.closeFn(error);
2173
- throw error;
2174
- }
2175
- }
2214
+ this.validateAndProcessRuntimeMessage(
2215
+ message,
2216
+ localOpMetadata,
2217
+ local,
2218
+ modernRuntimeMessage,
2219
+ );
2176
2220
 
2177
- this.emit("op", message, runtimeMessage);
2221
+ this.emit("op", message, modernRuntimeMessage);
2178
2222
 
2179
2223
  this.scheduleManager.afterOpProcessing(undefined, message);
2180
2224
 
@@ -2189,13 +2233,74 @@ export class ContainerRuntime
2189
2233
  throw e;
2190
2234
  }
2191
2235
  }
2192
-
2193
- private processAliasMessage(
2236
+ /**
2237
+ * Assuming the given message is also a ContainerRuntimeMessage,
2238
+ * checks its type and dispatches the message to the appropriate handler in the runtime.
2239
+ * Throws a DataProcessingError if the message doesn't conform to the ContainerRuntimeMessage type.
2240
+ */
2241
+ private validateAndProcessRuntimeMessage(
2194
2242
  message: ISequencedDocumentMessage,
2195
2243
  localOpMetadata: unknown,
2196
2244
  local: boolean,
2197
- ) {
2198
- this.dataStores.processAliasMessage(message, localOpMetadata, local);
2245
+ expectRuntimeMessageType: boolean,
2246
+ ): asserts message is SequencedContainerRuntimeMessage {
2247
+ // Optimistically extract ContainerRuntimeMessage-specific props from the message
2248
+ const { type: maybeContainerMessageType, compatDetails } =
2249
+ message as ContainerRuntimeMessage;
2250
+
2251
+ switch (maybeContainerMessageType) {
2252
+ case ContainerMessageType.Attach:
2253
+ this.dataStores.processAttachMessage(message, local);
2254
+ break;
2255
+ case ContainerMessageType.Alias:
2256
+ this.dataStores.processAliasMessage(message, localOpMetadata, local);
2257
+ break;
2258
+ case ContainerMessageType.FluidDataStoreOp:
2259
+ this.dataStores.processFluidDataStoreOp(message, local, localOpMetadata);
2260
+ break;
2261
+ case ContainerMessageType.BlobAttach:
2262
+ this.blobManager.processBlobAttachOp(message, local);
2263
+ break;
2264
+ case ContainerMessageType.IdAllocation:
2265
+ assert(
2266
+ this.idCompressor !== undefined,
2267
+ 0x67c /* IdCompressor should be defined if enabled */,
2268
+ );
2269
+ this.idCompressor.finalizeCreationRange(message.contents as IdCreationRange);
2270
+ break;
2271
+ case ContainerMessageType.ChunkedOp:
2272
+ case ContainerMessageType.Rejoin:
2273
+ break;
2274
+ default: {
2275
+ // If we didn't necessarily expect a runtime message type, then no worries - just return
2276
+ // e.g. this case applies to system ops, or legacy ops that would have fallen into the above cases anyway.
2277
+ if (!expectRuntimeMessageType) {
2278
+ return;
2279
+ }
2280
+
2281
+ const compatBehavior = compatDetails?.behavior;
2282
+ if (!compatBehaviorAllowsMessageType(maybeContainerMessageType, compatBehavior)) {
2283
+ const error = DataProcessingError.create(
2284
+ // Former assert 0x3ce
2285
+ "Runtime message of unknown type",
2286
+ "OpProcessing",
2287
+ message,
2288
+ {
2289
+ local,
2290
+ messageDetails: JSON.stringify({
2291
+ type: message.type,
2292
+ contentType: typeof message.contents,
2293
+ compatBehavior,
2294
+ batch: (message.metadata as IBatchMetadata | undefined)?.batch,
2295
+ compression: message.compression,
2296
+ }),
2297
+ },
2298
+ );
2299
+ this.closeFn(error);
2300
+ throw error;
2301
+ }
2302
+ }
2303
+ }
2199
2304
  }
2200
2305
 
2201
2306
  /**
@@ -2834,7 +2939,7 @@ export class ContainerRuntime
2834
2939
  * @param options - options controlling how the summary is generated or submitted
2835
2940
  */
2836
2941
  public async submitSummary(options: ISubmitSummaryOptions): Promise<SubmitSummaryResult> {
2837
- const { fullTree = false, refreshLatestAck, summaryLogger } = options;
2942
+ const { fullTree = false, finalAttempt = false, refreshLatestAck, summaryLogger } = options;
2838
2943
  // The summary number for this summary. This will be updated during the summary process, so get it now and
2839
2944
  // use it for all events logged during this summary.
2840
2945
  const summaryNumber = this.nextSummaryNumber;
@@ -2952,9 +3057,9 @@ export class ContainerRuntime
2952
3057
  };
2953
3058
  }
2954
3059
 
2955
- // If validateSummaryBeforeUpload is true, validate that the summary generated by the summarizer nodes is
2956
- // correct before this summary is uploaded.
3060
+ // If validateSummaryBeforeUpload is true, validate that the summary generated is correct before uploading.
2957
3061
  if (this.validateSummaryBeforeUpload) {
3062
+ // Validate that the summaries generated by summarize nodes is correct.
2958
3063
  const validateResult = this.summarizerNode.validateSummary();
2959
3064
  if (!validateResult.success) {
2960
3065
  const { success, ...loggingProps } = validateResult;
@@ -2970,6 +3075,49 @@ export class ContainerRuntime
2970
3075
  error,
2971
3076
  };
2972
3077
  }
3078
+
3079
+ // If there are pending messages, the summary has more data than at the summaryRefSeqNum.
3080
+ if (this.hasPendingMessages()) {
3081
+ // If "SkipFailingIncorrectSummary" option is true, don't fail the summary in the last attempt.
3082
+ // This is a fallback to make progress in documents where there are consistently pending ops in
3083
+ // the summarizer.
3084
+ if (
3085
+ finalAttempt &&
3086
+ this.mc.config.getBoolean("Fluid.Summarizer.SkipFailingIncorrectSummary")
3087
+ ) {
3088
+ const error = DataProcessingError.create(
3089
+ "Pending ops during summarization",
3090
+ "submitSummary",
3091
+ undefined,
3092
+ { pendingMessages: this.pendingMessagesCount },
3093
+ );
3094
+ summaryNumberLogger.sendErrorEvent(
3095
+ {
3096
+ eventName: "SkipFailingIncorrectSummary",
3097
+ referenceSequenceNumber: summaryRefSeqNum,
3098
+ minimumSequenceNumber,
3099
+ },
3100
+ error,
3101
+ );
3102
+ } else {
3103
+ // Default retry delay is 1 second. This can be overridden via config so that we can adjust it
3104
+ // based on telemetry while we decide on a stable number.
3105
+ const retryDelayMs =
3106
+ this.mc.config.getNumber("Fluid.Summarizer.PendingOpsRetryDelayMs") ??
3107
+ 1000;
3108
+ const error = new RetriableSummaryError(
3109
+ "PendingMessagesInSummary",
3110
+ retryDelayMs / 1000,
3111
+ { count: this.pendingMessagesCount },
3112
+ );
3113
+ return {
3114
+ stage: "base",
3115
+ referenceSequenceNumber: summaryRefSeqNum,
3116
+ minimumSequenceNumber,
3117
+ error,
3118
+ };
3119
+ }
3120
+ }
2973
3121
  }
2974
3122
 
2975
3123
  const { summary: summaryTree, stats: partialStats } = summarizeResult;
@@ -3110,8 +3258,12 @@ export class ContainerRuntime
3110
3258
  }
3111
3259
  }
3112
3260
 
3261
+ private get pendingMessagesCount(): number {
3262
+ return this.pendingStateManager.pendingMessagesCount + this.outbox.messageCount;
3263
+ }
3264
+
3113
3265
  private hasPendingMessages() {
3114
- return this.pendingStateManager.hasPendingMessages() || !this.outbox.isEmpty;
3266
+ return this.pendingMessagesCount !== 0;
3115
3267
  }
3116
3268
 
3117
3269
  private updateDocumentDirtyState(dirty: boolean) {
@@ -3178,7 +3330,7 @@ export class ContainerRuntime
3178
3330
  );
3179
3331
  idRange = this.idCompressor.takeNextCreationRange();
3180
3332
  // Don't include the idRange if there weren't any Ids allocated
3181
- idRange = idRange?.ids?.first !== undefined ? idRange : undefined;
3333
+ idRange = idRange?.ids !== undefined ? idRange : undefined;
3182
3334
  }
3183
3335
 
3184
3336
  if (idRange !== undefined) {
@@ -3439,11 +3591,31 @@ export class ContainerRuntime
3439
3591
  case ContainerMessageType.Rejoin:
3440
3592
  this.submit(message);
3441
3593
  break;
3442
- default:
3443
- unreachableCase(
3444
- message.type,
3445
- `Unknown ContainerMessageType [type: ${message.type}]`,
3446
- );
3594
+ default: {
3595
+ // This case should be very rare - it would imply an op was stashed from a
3596
+ // future version of runtime code and now is being applied on an older version
3597
+ const compatBehavior = message.compatDetails?.behavior;
3598
+ if (compatBehaviorAllowsMessageType(message.type, compatBehavior)) {
3599
+ this.logger.sendTelemetryEvent({
3600
+ eventName: "resubmitUnrecognizedMessageTypeAllowed",
3601
+ messageDetails: { type: message.type, compatBehavior },
3602
+ });
3603
+ } else {
3604
+ const error = DataProcessingError.create(
3605
+ "Resubmitting runtime message of unknown type",
3606
+ "reSubmitCore",
3607
+ undefined /* sequencedMessage */,
3608
+ {
3609
+ messageDetails: JSON.stringify({
3610
+ type: message.type,
3611
+ compatBehavior,
3612
+ }),
3613
+ },
3614
+ );
3615
+ this.closeFn(error);
3616
+ throw error;
3617
+ }
3618
+ }
3447
3619
  }
3448
3620
  }
3449
3621
 
@@ -3457,6 +3629,7 @@ export class ContainerRuntime
3457
3629
  this.dataStores.rollbackDataStoreOp(contents as IEnvelope, localOpMetadata);
3458
3630
  break;
3459
3631
  default:
3632
+ // Don't check message.compatDetails because this is for rolling back a local op so the type will be known
3460
3633
  throw new Error(`Can't rollback ${type}`);
3461
3634
  }
3462
3635
  }
@@ -3489,7 +3662,7 @@ export class ContainerRuntime
3489
3662
  // It should only be done by the summarizerNode, if required.
3490
3663
  // When fetching from storage we will always get the latest version and do not use the ackHandle.
3491
3664
  const fetchLatestSnapshot: () => Promise<IFetchSnapshotResult> = async () => {
3492
- let fetchResult = await this.fetchLatestSnapshotFromStorage(
3665
+ let fetchResult = await this.fetchSnapshotFromStorageAndMaybeClose(
3493
3666
  summaryLogger,
3494
3667
  {
3495
3668
  eventName: "RefreshLatestSummaryAckFetch",
@@ -3497,6 +3670,7 @@ export class ContainerRuntime
3497
3670
  targetSequenceNumber: summaryRefSeq,
3498
3671
  },
3499
3672
  readAndParseBlob,
3673
+ null,
3500
3674
  );
3501
3675
 
3502
3676
  /**
@@ -3506,7 +3680,7 @@ export class ContainerRuntime
3506
3680
  * change that started fetching latest snapshot always.
3507
3681
  */
3508
3682
  if (fetchResult.latestSnapshotRefSeq < summaryRefSeq) {
3509
- fetchResult = await this.fetchSnapshotFromStorageAndClose(
3683
+ fetchResult = await this.fetchSnapshotFromStorageAndMaybeClose(
3510
3684
  summaryLogger,
3511
3685
  {
3512
3686
  eventName: "RefreshLatestSummaryAckFetchBackCompat",
@@ -3579,12 +3753,13 @@ export class ContainerRuntime
3579
3753
  ): Promise<{ latestSnapshotRefSeq: number; latestSnapshotVersionId: string | undefined }> {
3580
3754
  const readAndParseBlob = async <T>(id: string) => readAndParse<T>(this.storage, id);
3581
3755
  const { snapshotTree, versionId, latestSnapshotRefSeq } =
3582
- await this.fetchLatestSnapshotFromStorage(
3756
+ await this.fetchSnapshotFromStorageAndMaybeClose(
3583
3757
  summaryLogger,
3584
3758
  {
3585
3759
  eventName: "RefreshLatestSummaryFromServerFetch",
3586
3760
  },
3587
3761
  readAndParseBlob,
3762
+ null,
3588
3763
  );
3589
3764
  const fetchLatestSnapshot: IFetchSnapshotResult = {
3590
3765
  snapshotTree,
@@ -3608,20 +3783,12 @@ export class ContainerRuntime
3608
3783
  return { latestSnapshotRefSeq, latestSnapshotVersionId: versionId };
3609
3784
  }
3610
3785
 
3611
- private async fetchLatestSnapshotFromStorage(
3612
- logger: ITelemetryLoggerExt,
3613
- event: ITelemetryGenericEvent,
3614
- readAndParseBlob: ReadAndParseBlob,
3615
- ): Promise<{ snapshotTree: ISnapshotTree; versionId: string; latestSnapshotRefSeq: number }> {
3616
- return this.fetchSnapshotFromStorageAndClose(
3617
- logger,
3618
- event,
3619
- readAndParseBlob,
3620
- null /* latest */,
3621
- );
3622
- }
3623
-
3624
- private async fetchSnapshotFromStorageAndClose(
3786
+ /**
3787
+ * Downloads snapshot from storage with the given versionId or latest if versionId is null.
3788
+ * By default, it also closes the container after downloading the snapshot. However, this may be
3789
+ * overridden via options.
3790
+ */
3791
+ private async fetchSnapshotFromStorageAndMaybeClose(
3625
3792
  logger: ITelemetryLoggerExt,
3626
3793
  event: ITelemetryGenericEvent,
3627
3794
  readAndParseBlob: ReadAndParseBlob,
@@ -3710,42 +3877,48 @@ export class ContainerRuntime
3710
3877
  throw new UsageError("can't get state during orderSequentially");
3711
3878
  }
3712
3879
  const pendingAttachmentBlobs = await this.blobManager.getPendingBlobs(waitBlobsToAttach);
3880
+
3881
+ if (!pendingAttachmentBlobs && !this.hasPendingMessages()) {
3882
+ return; // no pending state to save
3883
+ }
3884
+
3713
3885
  // Flush pending batch.
3714
3886
  // getPendingLocalState() is only exposed through Container.closeAndGetPendingLocalState(), so it's safe
3715
3887
  // to close current batch.
3716
3888
  this.flush();
3717
3889
 
3718
- return {
3890
+ const pendingState: IPendingRuntimeState = {
3719
3891
  pending: this.pendingStateManager.getLocalState(),
3720
3892
  pendingAttachmentBlobs,
3721
3893
  };
3894
+ return pendingState;
3722
3895
  }
3723
3896
 
3724
- public readonly summarizeOnDemand: ISummarizer["summarizeOnDemand"] = (...args) => {
3897
+ public summarizeOnDemand(options: IOnDemandSummarizeOptions): ISummarizeResults {
3725
3898
  if (this.isSummarizerClient) {
3726
- return this.summarizer.summarizeOnDemand(...args);
3899
+ return this.summarizer.summarizeOnDemand(options);
3727
3900
  } else if (this.summaryManager !== undefined) {
3728
- return this.summaryManager.summarizeOnDemand(...args);
3901
+ return this.summaryManager.summarizeOnDemand(options);
3729
3902
  } else {
3730
3903
  // If we're not the summarizer, and we don't have a summaryManager, we expect that
3731
3904
  // disableSummaries is turned on. We are throwing instead of returning a failure here,
3732
3905
  // because it is a misuse of the API rather than an expected failure.
3733
3906
  throw new UsageError(`Can't summarize, disableSummaries: ${this.summariesDisabled}`);
3734
3907
  }
3735
- };
3908
+ }
3736
3909
 
3737
- public readonly enqueueSummarize: ISummarizer["enqueueSummarize"] = (...args) => {
3910
+ public enqueueSummarize(options: IEnqueueSummarizeOptions): EnqueueSummarizeResult {
3738
3911
  if (this.isSummarizerClient) {
3739
- return this.summarizer.enqueueSummarize(...args);
3912
+ return this.summarizer.enqueueSummarize(options);
3740
3913
  } else if (this.summaryManager !== undefined) {
3741
- return this.summaryManager.enqueueSummarize(...args);
3914
+ return this.summaryManager.enqueueSummarize(options);
3742
3915
  } else {
3743
3916
  // If we're not the summarizer, and we don't have a summaryManager, we expect that
3744
3917
  // generateSummaries is turned off. We are throwing instead of returning a failure here,
3745
3918
  // because it is a misuse of the API rather than an expected failure.
3746
3919
  throw new UsageError(`Can't summarize, disableSummaries: ${this.summariesDisabled}`);
3747
3920
  }
3748
- };
3921
+ }
3749
3922
 
3750
3923
  /**
3751
3924
  * * Forms a function that will request a Summarizer.