@fluidframework/container-runtime 2.0.0-internal.6.2.0 → 2.0.0-internal.6.3.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 (310) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/dist/batchTracker.d.ts.map +1 -1
  3. package/dist/batchTracker.js +4 -3
  4. package/dist/batchTracker.js.map +1 -1
  5. package/dist/blobManager.d.ts +1 -2
  6. package/dist/blobManager.d.ts.map +1 -1
  7. package/dist/blobManager.js +81 -69
  8. package/dist/blobManager.js.map +1 -1
  9. package/dist/connectionTelemetry.d.ts.map +1 -1
  10. package/dist/connectionTelemetry.js +13 -12
  11. package/dist/connectionTelemetry.js.map +1 -1
  12. package/dist/containerRuntime.d.ts +18 -3
  13. package/dist/containerRuntime.d.ts.map +1 -1
  14. package/dist/containerRuntime.js +185 -145
  15. package/dist/containerRuntime.js.map +1 -1
  16. package/dist/dataStore.js +3 -3
  17. package/dist/dataStore.js.map +1 -1
  18. package/dist/dataStoreContext.d.ts +2 -1
  19. package/dist/dataStoreContext.d.ts.map +1 -1
  20. package/dist/dataStoreContext.js +36 -36
  21. package/dist/dataStoreContext.js.map +1 -1
  22. package/dist/dataStoreContexts.d.ts.map +1 -1
  23. package/dist/dataStoreContexts.js +7 -8
  24. package/dist/dataStoreContexts.js.map +1 -1
  25. package/dist/dataStores.d.ts.map +1 -1
  26. package/dist/dataStores.js +19 -20
  27. package/dist/dataStores.js.map +1 -1
  28. package/dist/deltaManagerProxyBase.d.ts +1 -1
  29. package/dist/deltaManagerProxyBase.js +2 -2
  30. package/dist/deltaManagerProxyBase.js.map +1 -1
  31. package/dist/deltaScheduler.js +6 -6
  32. package/dist/deltaScheduler.js.map +1 -1
  33. package/dist/gc/garbageCollection.d.ts +3 -5
  34. package/dist/gc/garbageCollection.d.ts.map +1 -1
  35. package/dist/gc/garbageCollection.js +4 -21
  36. package/dist/gc/garbageCollection.js.map +1 -1
  37. package/dist/gc/gcDefinitions.d.ts +2 -2
  38. package/dist/gc/gcDefinitions.d.ts.map +1 -1
  39. package/dist/gc/gcDefinitions.js.map +1 -1
  40. package/dist/gc/gcHelpers.js +7 -7
  41. package/dist/gc/gcHelpers.js.map +1 -1
  42. package/dist/gc/gcSummaryStateTracker.d.ts +4 -7
  43. package/dist/gc/gcSummaryStateTracker.d.ts.map +1 -1
  44. package/dist/gc/gcSummaryStateTracker.js +15 -52
  45. package/dist/gc/gcSummaryStateTracker.js.map +1 -1
  46. package/dist/gc/gcUnreferencedStateTracker.js +4 -4
  47. package/dist/gc/gcUnreferencedStateTracker.js.map +1 -1
  48. package/dist/gc/index.d.ts +1 -1
  49. package/dist/gc/index.d.ts.map +1 -1
  50. package/dist/gc/index.js +1 -2
  51. package/dist/gc/index.js.map +1 -1
  52. package/dist/id-compressor/appendOnlySortedMap.js +2 -2
  53. package/dist/id-compressor/appendOnlySortedMap.js.map +1 -1
  54. package/dist/id-compressor/finalSpace.js +2 -2
  55. package/dist/id-compressor/finalSpace.js.map +1 -1
  56. package/dist/id-compressor/idCompressor.d.ts.map +1 -1
  57. package/dist/id-compressor/idCompressor.js +16 -15
  58. package/dist/id-compressor/idCompressor.js.map +1 -1
  59. package/dist/id-compressor/sessions.js +5 -5
  60. package/dist/id-compressor/sessions.js.map +1 -1
  61. package/dist/id-compressor/utilities.js +2 -2
  62. package/dist/id-compressor/utilities.js.map +1 -1
  63. package/dist/opLifecycle/opCompressor.d.ts.map +1 -1
  64. package/dist/opLifecycle/opCompressor.js +4 -3
  65. package/dist/opLifecycle/opCompressor.js.map +1 -1
  66. package/dist/opLifecycle/opDecompressor.d.ts.map +1 -1
  67. package/dist/opLifecycle/opDecompressor.js +11 -10
  68. package/dist/opLifecycle/opDecompressor.js.map +1 -1
  69. package/dist/opLifecycle/opGroupingManager.js +3 -3
  70. package/dist/opLifecycle/opGroupingManager.js.map +1 -1
  71. package/dist/opLifecycle/opSplitter.js +12 -12
  72. package/dist/opLifecycle/opSplitter.js.map +1 -1
  73. package/dist/opLifecycle/outbox.js +6 -6
  74. package/dist/opLifecycle/outbox.js.map +1 -1
  75. package/dist/packageVersion.d.ts +1 -1
  76. package/dist/packageVersion.js +1 -1
  77. package/dist/packageVersion.js.map +1 -1
  78. package/dist/pendingStateManager.d.ts.map +1 -1
  79. package/dist/pendingStateManager.js +12 -13
  80. package/dist/pendingStateManager.js.map +1 -1
  81. package/dist/scheduleManager.d.ts.map +1 -1
  82. package/dist/scheduleManager.js +19 -18
  83. package/dist/scheduleManager.js.map +1 -1
  84. package/dist/summary/index.d.ts +1 -1
  85. package/dist/summary/index.d.ts.map +1 -1
  86. package/dist/summary/index.js.map +1 -1
  87. package/dist/summary/orderedClientElection.d.ts +1 -1
  88. package/dist/summary/orderedClientElection.d.ts.map +1 -1
  89. package/dist/summary/orderedClientElection.js +6 -5
  90. package/dist/summary/orderedClientElection.js.map +1 -1
  91. package/dist/summary/runWhileConnectedCoordinator.js +3 -3
  92. package/dist/summary/runWhileConnectedCoordinator.js.map +1 -1
  93. package/dist/summary/runningSummarizer.d.ts +1 -1
  94. package/dist/summary/runningSummarizer.d.ts.map +1 -1
  95. package/dist/summary/runningSummarizer.js +13 -12
  96. package/dist/summary/runningSummarizer.js.map +1 -1
  97. package/dist/summary/summarizer.d.ts +1 -1
  98. package/dist/summary/summarizer.d.ts.map +1 -1
  99. package/dist/summary/summarizer.js +4 -3
  100. package/dist/summary/summarizer.js.map +1 -1
  101. package/dist/summary/summarizerClientElection.d.ts +1 -1
  102. package/dist/summary/summarizerClientElection.js +2 -2
  103. package/dist/summary/summarizerClientElection.js.map +1 -1
  104. package/dist/summary/summarizerHeuristics.js +2 -2
  105. package/dist/summary/summarizerHeuristics.js.map +1 -1
  106. package/dist/summary/summarizerNode/index.d.ts +1 -1
  107. package/dist/summary/summarizerNode/index.d.ts.map +1 -1
  108. package/dist/summary/summarizerNode/index.js.map +1 -1
  109. package/dist/summary/summarizerNode/summarizerNode.d.ts +5 -14
  110. package/dist/summary/summarizerNode/summarizerNode.d.ts.map +1 -1
  111. package/dist/summary/summarizerNode/summarizerNode.js +32 -109
  112. package/dist/summary/summarizerNode/summarizerNode.js.map +1 -1
  113. package/dist/summary/summarizerNode/summarizerNodeUtils.d.ts +6 -30
  114. package/dist/summary/summarizerNode/summarizerNodeUtils.d.ts.map +1 -1
  115. package/dist/summary/summarizerNode/summarizerNodeUtils.js.map +1 -1
  116. package/dist/summary/summarizerNode/summarizerNodeWithGc.d.ts +0 -11
  117. package/dist/summary/summarizerNode/summarizerNodeWithGc.d.ts.map +1 -1
  118. package/dist/summary/summarizerNode/summarizerNodeWithGc.js +5 -88
  119. package/dist/summary/summarizerNode/summarizerNodeWithGc.js.map +1 -1
  120. package/dist/summary/summaryCollection.d.ts +1 -1
  121. package/dist/summary/summaryCollection.d.ts.map +1 -1
  122. package/dist/summary/summaryCollection.js +9 -8
  123. package/dist/summary/summaryCollection.js.map +1 -1
  124. package/dist/summary/summaryFormat.js +2 -2
  125. package/dist/summary/summaryFormat.js.map +1 -1
  126. package/dist/summary/summaryGenerator.d.ts +1 -1
  127. package/dist/summary/summaryGenerator.d.ts.map +1 -1
  128. package/dist/summary/summaryGenerator.js +10 -10
  129. package/dist/summary/summaryGenerator.js.map +1 -1
  130. package/dist/summary/summaryManager.d.ts +1 -1
  131. package/dist/summary/summaryManager.d.ts.map +1 -1
  132. package/dist/summary/summaryManager.js +9 -8
  133. package/dist/summary/summaryManager.js.map +1 -1
  134. package/lib/batchTracker.d.ts.map +1 -1
  135. package/lib/batchTracker.js +2 -1
  136. package/lib/batchTracker.js.map +1 -1
  137. package/lib/blobManager.d.ts +1 -2
  138. package/lib/blobManager.d.ts.map +1 -1
  139. package/lib/blobManager.js +52 -40
  140. package/lib/blobManager.js.map +1 -1
  141. package/lib/connectionTelemetry.d.ts.map +1 -1
  142. package/lib/connectionTelemetry.js +2 -1
  143. package/lib/connectionTelemetry.js.map +1 -1
  144. package/lib/containerRuntime.d.ts +18 -3
  145. package/lib/containerRuntime.d.ts.map +1 -1
  146. package/lib/containerRuntime.js +147 -107
  147. package/lib/containerRuntime.js.map +1 -1
  148. package/lib/dataStore.js +1 -1
  149. package/lib/dataStore.js.map +1 -1
  150. package/lib/dataStoreContext.d.ts +2 -1
  151. package/lib/dataStoreContext.d.ts.map +1 -1
  152. package/lib/dataStoreContext.js +2 -2
  153. package/lib/dataStoreContext.js.map +1 -1
  154. package/lib/dataStoreContexts.d.ts.map +1 -1
  155. package/lib/dataStoreContexts.js +1 -2
  156. package/lib/dataStoreContexts.js.map +1 -1
  157. package/lib/dataStores.d.ts.map +1 -1
  158. package/lib/dataStores.js +1 -2
  159. package/lib/dataStores.js.map +1 -1
  160. package/lib/deltaManagerProxyBase.d.ts +1 -1
  161. package/lib/deltaManagerProxyBase.js +1 -1
  162. package/lib/deltaManagerProxyBase.js.map +1 -1
  163. package/lib/deltaScheduler.js +1 -1
  164. package/lib/deltaScheduler.js.map +1 -1
  165. package/lib/gc/garbageCollection.d.ts +3 -5
  166. package/lib/gc/garbageCollection.d.ts.map +1 -1
  167. package/lib/gc/garbageCollection.js +5 -22
  168. package/lib/gc/garbageCollection.js.map +1 -1
  169. package/lib/gc/gcDefinitions.d.ts +2 -2
  170. package/lib/gc/gcDefinitions.d.ts.map +1 -1
  171. package/lib/gc/gcDefinitions.js.map +1 -1
  172. package/lib/gc/gcHelpers.js +1 -1
  173. package/lib/gc/gcHelpers.js.map +1 -1
  174. package/lib/gc/gcSummaryStateTracker.d.ts +4 -7
  175. package/lib/gc/gcSummaryStateTracker.d.ts.map +1 -1
  176. package/lib/gc/gcSummaryStateTracker.js +16 -53
  177. package/lib/gc/gcSummaryStateTracker.js.map +1 -1
  178. package/lib/gc/gcUnreferencedStateTracker.js +1 -1
  179. package/lib/gc/gcUnreferencedStateTracker.js.map +1 -1
  180. package/lib/gc/index.d.ts +1 -1
  181. package/lib/gc/index.d.ts.map +1 -1
  182. package/lib/gc/index.js +1 -1
  183. package/lib/gc/index.js.map +1 -1
  184. package/lib/id-compressor/appendOnlySortedMap.js +1 -1
  185. package/lib/id-compressor/appendOnlySortedMap.js.map +1 -1
  186. package/lib/id-compressor/finalSpace.js +1 -1
  187. package/lib/id-compressor/finalSpace.js.map +1 -1
  188. package/lib/id-compressor/idCompressor.d.ts.map +1 -1
  189. package/lib/id-compressor/idCompressor.js +2 -1
  190. package/lib/id-compressor/idCompressor.js.map +1 -1
  191. package/lib/id-compressor/sessions.js +1 -1
  192. package/lib/id-compressor/sessions.js.map +1 -1
  193. package/lib/id-compressor/utilities.js +1 -1
  194. package/lib/id-compressor/utilities.js.map +1 -1
  195. package/lib/opLifecycle/opCompressor.d.ts.map +1 -1
  196. package/lib/opLifecycle/opCompressor.js +2 -1
  197. package/lib/opLifecycle/opCompressor.js.map +1 -1
  198. package/lib/opLifecycle/opDecompressor.d.ts.map +1 -1
  199. package/lib/opLifecycle/opDecompressor.js +2 -1
  200. package/lib/opLifecycle/opDecompressor.js.map +1 -1
  201. package/lib/opLifecycle/opGroupingManager.js +1 -1
  202. package/lib/opLifecycle/opGroupingManager.js.map +1 -1
  203. package/lib/opLifecycle/opSplitter.js +1 -1
  204. package/lib/opLifecycle/opSplitter.js.map +1 -1
  205. package/lib/opLifecycle/outbox.js +1 -1
  206. package/lib/opLifecycle/outbox.js.map +1 -1
  207. package/lib/packageVersion.d.ts +1 -1
  208. package/lib/packageVersion.js +1 -1
  209. package/lib/packageVersion.js.map +1 -1
  210. package/lib/pendingStateManager.d.ts.map +1 -1
  211. package/lib/pendingStateManager.js +1 -2
  212. package/lib/pendingStateManager.js.map +1 -1
  213. package/lib/scheduleManager.d.ts.map +1 -1
  214. package/lib/scheduleManager.js +2 -1
  215. package/lib/scheduleManager.js.map +1 -1
  216. package/lib/summary/index.d.ts +1 -1
  217. package/lib/summary/index.d.ts.map +1 -1
  218. package/lib/summary/index.js.map +1 -1
  219. package/lib/summary/orderedClientElection.d.ts +1 -1
  220. package/lib/summary/orderedClientElection.d.ts.map +1 -1
  221. package/lib/summary/orderedClientElection.js +2 -1
  222. package/lib/summary/orderedClientElection.js.map +1 -1
  223. package/lib/summary/runWhileConnectedCoordinator.js +1 -1
  224. package/lib/summary/runWhileConnectedCoordinator.js.map +1 -1
  225. package/lib/summary/runningSummarizer.d.ts +1 -1
  226. package/lib/summary/runningSummarizer.d.ts.map +1 -1
  227. package/lib/summary/runningSummarizer.js +5 -4
  228. package/lib/summary/runningSummarizer.js.map +1 -1
  229. package/lib/summary/summarizer.d.ts +1 -1
  230. package/lib/summary/summarizer.d.ts.map +1 -1
  231. package/lib/summary/summarizer.js +2 -1
  232. package/lib/summary/summarizer.js.map +1 -1
  233. package/lib/summary/summarizerClientElection.d.ts +1 -1
  234. package/lib/summary/summarizerClientElection.js +1 -1
  235. package/lib/summary/summarizerClientElection.js.map +1 -1
  236. package/lib/summary/summarizerHeuristics.js +1 -1
  237. package/lib/summary/summarizerHeuristics.js.map +1 -1
  238. package/lib/summary/summarizerNode/index.d.ts +1 -1
  239. package/lib/summary/summarizerNode/index.d.ts.map +1 -1
  240. package/lib/summary/summarizerNode/index.js.map +1 -1
  241. package/lib/summary/summarizerNode/summarizerNode.d.ts +5 -14
  242. package/lib/summary/summarizerNode/summarizerNode.d.ts.map +1 -1
  243. package/lib/summary/summarizerNode/summarizerNode.js +16 -93
  244. package/lib/summary/summarizerNode/summarizerNode.js.map +1 -1
  245. package/lib/summary/summarizerNode/summarizerNodeUtils.d.ts +6 -30
  246. package/lib/summary/summarizerNode/summarizerNodeUtils.d.ts.map +1 -1
  247. package/lib/summary/summarizerNode/summarizerNodeUtils.js.map +1 -1
  248. package/lib/summary/summarizerNode/summarizerNodeWithGc.d.ts +0 -11
  249. package/lib/summary/summarizerNode/summarizerNodeWithGc.d.ts.map +1 -1
  250. package/lib/summary/summarizerNode/summarizerNodeWithGc.js +3 -86
  251. package/lib/summary/summarizerNode/summarizerNodeWithGc.js.map +1 -1
  252. package/lib/summary/summaryCollection.d.ts +1 -1
  253. package/lib/summary/summaryCollection.d.ts.map +1 -1
  254. package/lib/summary/summaryCollection.js +2 -1
  255. package/lib/summary/summaryCollection.js.map +1 -1
  256. package/lib/summary/summaryFormat.js +1 -1
  257. package/lib/summary/summaryFormat.js.map +1 -1
  258. package/lib/summary/summaryGenerator.d.ts +1 -1
  259. package/lib/summary/summaryGenerator.d.ts.map +1 -1
  260. package/lib/summary/summaryGenerator.js +3 -3
  261. package/lib/summary/summaryGenerator.js.map +1 -1
  262. package/lib/summary/summaryManager.d.ts +1 -1
  263. package/lib/summary/summaryManager.d.ts.map +1 -1
  264. package/lib/summary/summaryManager.js +4 -3
  265. package/lib/summary/summaryManager.js.map +1 -1
  266. package/package.json +22 -24
  267. package/src/batchTracker.ts +2 -1
  268. package/src/blobManager.ts +57 -48
  269. package/src/connectionTelemetry.ts +2 -1
  270. package/src/containerRuntime.ts +207 -166
  271. package/src/dataStore.ts +1 -1
  272. package/src/dataStoreContext.ts +2 -2
  273. package/src/dataStoreContexts.ts +1 -2
  274. package/src/dataStores.ts +1 -2
  275. package/src/deltaManagerProxyBase.ts +1 -1
  276. package/src/deltaScheduler.ts +1 -1
  277. package/src/gc/garbageCollection.ts +6 -41
  278. package/src/gc/gcDefinitions.ts +2 -6
  279. package/src/gc/gcHelpers.ts +1 -1
  280. package/src/gc/gcSummaryStateTracker.ts +19 -65
  281. package/src/gc/gcUnreferencedStateTracker.ts +1 -1
  282. package/src/gc/index.ts +0 -1
  283. package/src/id-compressor/appendOnlySortedMap.ts +1 -1
  284. package/src/id-compressor/finalSpace.ts +1 -1
  285. package/src/id-compressor/idCompressor.ts +2 -1
  286. package/src/id-compressor/sessions.ts +1 -1
  287. package/src/id-compressor/utilities.ts +1 -1
  288. package/src/opLifecycle/opCompressor.ts +2 -1
  289. package/src/opLifecycle/opDecompressor.ts +2 -1
  290. package/src/opLifecycle/opGroupingManager.ts +1 -1
  291. package/src/opLifecycle/opSplitter.ts +1 -1
  292. package/src/opLifecycle/outbox.ts +1 -1
  293. package/src/packageVersion.ts +1 -1
  294. package/src/pendingStateManager.ts +1 -2
  295. package/src/scheduleManager.ts +2 -1
  296. package/src/summary/index.ts +1 -2
  297. package/src/summary/orderedClientElection.ts +2 -1
  298. package/src/summary/runWhileConnectedCoordinator.ts +1 -1
  299. package/src/summary/runningSummarizer.ts +5 -10
  300. package/src/summary/summarizer.ts +2 -1
  301. package/src/summary/summarizerClientElection.ts +1 -1
  302. package/src/summary/summarizerHeuristics.ts +1 -1
  303. package/src/summary/summarizerNode/index.ts +1 -2
  304. package/src/summary/summarizerNode/summarizerNode.ts +23 -145
  305. package/src/summary/summarizerNode/summarizerNodeUtils.ts +7 -38
  306. package/src/summary/summarizerNode/summarizerNodeWithGc.ts +3 -123
  307. package/src/summary/summaryCollection.ts +2 -1
  308. package/src/summary/summaryFormat.ts +1 -1
  309. package/src/summary/summaryGenerator.ts +3 -3
  310. package/src/summary/summaryManager.ts +4 -3
@@ -19,10 +19,10 @@ var __importStar = (this && this.__importStar) || function (mod) {
19
19
  return result;
20
20
  };
21
21
  Object.defineProperty(exports, "__esModule", { value: true });
22
- exports.ContainerRuntime = exports.makeLegacySendBatchFn = exports.getDeviceSpec = exports.agentSchedulerId = exports.isRuntimeMessage = exports.RuntimeMessage = exports.CompressionAlgorithms = exports.defaultRuntimeHeaderData = exports.InactiveResponseHeaderKey = exports.TombstoneResponseHeaderKey = exports.AllowInactiveRequestHeaderKey = exports.AllowTombstoneRequestHeaderKey = exports.RuntimeHeaders = exports.DefaultSummaryConfiguration = exports.ContainerMessageType = void 0;
22
+ exports.ContainerRuntime = exports.makeLegacySendBatchFn = exports.getDeviceSpec = exports.agentSchedulerId = exports.isRuntimeMessage = exports.RuntimeMessage = exports.defaultPendingOpsRetryDelayMs = exports.defaultPendingOpsWaitTimeoutMs = exports.CompressionAlgorithms = exports.defaultRuntimeHeaderData = exports.InactiveResponseHeaderKey = exports.TombstoneResponseHeaderKey = exports.AllowInactiveRequestHeaderKey = exports.AllowTombstoneRequestHeaderKey = exports.RuntimeHeaders = exports.DefaultSummaryConfiguration = exports.ContainerMessageType = void 0;
23
23
  const container_definitions_1 = require("@fluidframework/container-definitions");
24
- const common_utils_1 = require("@fluidframework/common-utils");
25
24
  const core_utils_1 = require("@fluidframework/core-utils");
25
+ const client_utils_1 = require("@fluid-internal/client-utils");
26
26
  const telemetry_utils_1 = require("@fluidframework/telemetry-utils");
27
27
  const driver_definitions_1 = require("@fluidframework/driver-definitions");
28
28
  const driver_utils_1 = require("@fluidframework/driver-utils");
@@ -136,6 +136,10 @@ const defaultCompressionConfig = {
136
136
  compressionAlgorithm: CompressionAlgorithms.lz4,
137
137
  };
138
138
  const defaultChunkSizeInBytes = 204800;
139
+ /** The default time to wait for pending ops to be processed during summarization */
140
+ exports.defaultPendingOpsWaitTimeoutMs = 1000;
141
+ /** The default time to delay a summarization retry attempt when there are pending ops */
142
+ exports.defaultPendingOpsRetryDelayMs = 1000;
139
143
  /**
140
144
  * Instead of refreshing from latest because we do not have 100% confidence in the state
141
145
  * of the current system, we should close the summarizer and let it recover.
@@ -201,7 +205,7 @@ exports.makeLegacySendBatchFn = makeLegacySendBatchFn;
201
205
  * Represents the runtime of the container. Contains helper functions/state of the container.
202
206
  * It will define the store level mappings.
203
207
  */
204
- class ContainerRuntime extends common_utils_1.TypedEventEmitter {
208
+ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
205
209
  /**
206
210
  * @internal
207
211
  */
@@ -454,12 +458,10 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
454
458
  });
455
459
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
456
460
  this._audience = audience;
457
- this.summaryStateUpdateMethod = this.mc.config.getString("Fluid.ContainerRuntime.Test.SummaryStateUpdateMethodV2");
458
461
  const closeSummarizerDelayOverride = this.mc.config.getNumber("Fluid.ContainerRuntime.Test.CloseSummarizerDelayOverrideMs");
459
462
  this.closeSummarizerDelayMs = closeSummarizerDelayOverride ?? defaultCloseSummarizerDelayMs;
460
463
  this.validateSummaryBeforeUpload =
461
- this.mc.config.getBoolean("Fluid.ContainerRuntime.Test.ValidateSummaryBeforeUpload") ??
462
- false;
464
+ this.mc.config.getBoolean("Fluid.Summarizer.ValidateSummaryBeforeUpload") ?? false;
463
465
  this.summaryCollection = new summary_1.SummaryCollection(this.deltaManager, this.logger);
464
466
  this.dirtyContainer =
465
467
  this.attachState !== container_definitions_1.AttachState.Attached || this.hasPendingMessages();
@@ -520,7 +522,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
520
522
  // we accumulate ops while being in read-only state.
521
523
  // once user gets write permissions and we have active connection, flush all pending ops.
522
524
  // Note that the inner (non-proxy) delta manager is needed here to get the readonly information.
523
- (0, common_utils_1.assert)(readonly === this.innerDeltaManager.readOnlyInfo.readonly, 0x124 /* "inconsistent readonly property/event state" */);
525
+ (0, core_utils_1.assert)(readonly === this.innerDeltaManager.readOnlyInfo.readonly, 0x124 /* "inconsistent readonly property/event state" */);
524
526
  // We need to be very careful with when we (re)send pending ops, to ensure that we only send ops
525
527
  // when we either never send an op, or attempted to send it but we know for sure it was not
526
528
  // sequenced by server and will never be sequenced (i.e. was lost)
@@ -533,7 +535,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
533
535
  // can rely on same safety mechanism and resend ops only when we establish new connection.
534
536
  // This is applicable for read-only permissions (event is raised before connection is properly registered),
535
537
  // but it's an extra requirement for Container.forceReadonly() API
536
- (0, common_utils_1.assert)(!readonly || !this.connected, 0x125 /* "Unsafe to transition to read-only state!" */);
538
+ (0, core_utils_1.assert)(!readonly || !this.connected, 0x125 /* "Unsafe to transition to read-only state!" */);
537
539
  this.replayPendingStates();
538
540
  });
539
541
  // logging hardware telemetry
@@ -557,7 +559,6 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
557
559
  disableAttachReorder: this.disableAttachReorder,
558
560
  disablePartialFlush,
559
561
  idCompressorEnabled: this.idCompressorEnabled,
560
- summaryStateUpdateMethod: this.summaryStateUpdateMethod,
561
562
  closeSummarizerDelayOverride,
562
563
  }),
563
564
  telemetryDocumentId: this.telemetryDocumentId,
@@ -567,7 +568,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
567
568
  (0, batchTracker_1.BindBatchTracker)(this, this.logger);
568
569
  this.entryPoint = new core_utils_1.LazyPromise(async () => {
569
570
  if (this.isSummarizerClient) {
570
- (0, common_utils_1.assert)(this._summarizer !== undefined, 0x5bf /* Summarizer object is undefined in a summarizer client */);
571
+ (0, core_utils_1.assert)(this._summarizer !== undefined, 0x5bf /* Summarizer object is undefined in a summarizer client */);
571
572
  return this._summarizer;
572
573
  }
573
574
  return initializeEntryPoint?.(this);
@@ -652,7 +653,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
652
653
  if (context.baseSnapshot && blobId) {
653
654
  // IContainerContext storage api return type still has undefined in 0.39 package version.
654
655
  // So once we release 0.40 container-defn package we can remove this check.
655
- (0, common_utils_1.assert)(context.storage !== undefined, 0x1f5 /* "Attached state should have storage" */);
656
+ (0, core_utils_1.assert)(context.storage !== undefined, 0x1f5 /* "Attached state should have storage" */);
656
657
  return (0, driver_utils_1.readAndParse)(context.storage, blobId);
657
658
  }
658
659
  };
@@ -667,7 +668,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
667
668
  const blobManagerSnapshot = await blobManager_1.BlobManager.load(context.baseSnapshot?.trees[summary_1.blobsTreeName], async (id) => {
668
669
  // IContainerContext storage api return type still has undefined in 0.39 package version.
669
670
  // So once we release 0.40 container-defn package we can remove this check.
670
- (0, common_utils_1.assert)(context.storage !== undefined, 0x256 /* "storage undefined in attached container" */);
671
+ (0, core_utils_1.assert)(context.storage !== undefined, 0x256 /* "storage undefined in attached container" */);
671
672
  return (0, driver_utils_1.readAndParse)(context.storage, id);
672
673
  });
673
674
  // Verify summary runtime sequence number matches protocol sequence number.
@@ -774,7 +775,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
774
775
  return this._disposed;
775
776
  }
776
777
  get summarizer() {
777
- (0, common_utils_1.assert)(this._summarizer !== undefined, 0x257 /* "This is not summarizing container" */);
778
+ (0, core_utils_1.assert)(this._summarizer !== undefined, 0x257 /* "This is not summarizing container" */);
778
779
  return this._summarizer;
779
780
  }
780
781
  isSummariesDisabled() {
@@ -879,7 +880,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
879
880
  const subRequest = requestParser.createSubRequest(1);
880
881
  // We always expect createSubRequest to include a leading slash, but asserting here to protect against
881
882
  // unintentionally modifying the url if that changes.
882
- (0, common_utils_1.assert)(subRequest.url.startsWith("/"), 0x126 /* "Expected createSubRequest url to include a leading slash" */);
883
+ (0, core_utils_1.assert)(subRequest.url.startsWith("/"), 0x126 /* "Expected createSubRequest url to include a leading slash" */);
883
884
  return dataStore.request(subRequest);
884
885
  }
885
886
  return (0, runtime_utils_1.create404Response)(request);
@@ -938,7 +939,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
938
939
  addContainerStateToSummary(summaryTree, fullTree, trackState, telemetryContext) {
939
940
  this.addMetadataToSummary(summaryTree);
940
941
  if (this.idCompressorEnabled) {
941
- (0, common_utils_1.assert)(this.idCompressor !== undefined, 0x67a /* IdCompressor should be defined if enabled */);
942
+ (0, core_utils_1.assert)(this.idCompressor !== undefined, 0x67a /* IdCompressor should be defined if enabled */);
942
943
  const idCompressorState = JSON.stringify(this.idCompressor.serialize(false));
943
944
  (0, runtime_utils_1.addBlobToSummary)(summaryTree, summary_1.idCompressorBlobName, idCompressorState);
944
945
  }
@@ -1013,7 +1014,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1013
1014
  // Save the old state, reset to false, disable event emit
1014
1015
  const oldState = this.dirtyContainer;
1015
1016
  this.dirtyContainer = false;
1016
- (0, common_utils_1.assert)(this.emitDirtyDocumentEvent, 0x127 /* "dirty document event not set on replay" */);
1017
+ (0, core_utils_1.assert)(this.emitDirtyDocumentEvent, 0x127 /* "dirty document event not set on replay" */);
1017
1018
  this.emitDirtyDocumentEvent = false;
1018
1019
  let newState;
1019
1020
  try {
@@ -1047,9 +1048,9 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1047
1048
  * ! Note: this format needs to be in-line with what is set in the "ContainerRuntime.submit(...)" method
1048
1049
  */
1049
1050
  parseOpContent(serializedContent) {
1050
- (0, common_utils_1.assert)(serializedContent !== undefined, 0x6d5 /* content must be defined */);
1051
+ (0, core_utils_1.assert)(serializedContent !== undefined, 0x6d5 /* content must be defined */);
1051
1052
  const { type, contents, compatDetails } = JSON.parse(serializedContent);
1052
- (0, common_utils_1.assert)(type !== undefined, 0x6d6 /* incorrect op content format */);
1053
+ (0, core_utils_1.assert)(type !== undefined, 0x6d6 /* incorrect op content format */);
1053
1054
  return { type, contents, compatDetails };
1054
1055
  }
1055
1056
  async applyStashedOp(op) {
@@ -1061,7 +1062,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1061
1062
  case ContainerMessageType.Attach:
1062
1063
  return this.dataStores.applyStashedAttachOp(contents);
1063
1064
  case ContainerMessageType.IdAllocation:
1064
- (0, common_utils_1.assert)(this.idCompressor !== undefined, 0x67b /* IdCompressor should be defined if enabled */);
1065
+ (0, core_utils_1.assert)(this.idCompressor !== undefined, 0x67b /* IdCompressor should be defined if enabled */);
1065
1066
  return this.applyStashedIdAllocationOp(contents);
1066
1067
  case ContainerMessageType.Alias:
1067
1068
  case ContainerMessageType.BlobAttach:
@@ -1100,7 +1101,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1100
1101
  this.setConnectionStateCore(connected, clientId);
1101
1102
  }
1102
1103
  setConnectionStateCore(connected, clientId) {
1103
- (0, common_utils_1.assert)(!this.delayConnectClientId, 0x394 /* connect event delay must be cleared before propagating connect event */);
1104
+ (0, core_utils_1.assert)(!this.delayConnectClientId, 0x394 /* connect event delay must be cleared before propagating connect event */);
1104
1105
  this.verifyNotClosed();
1105
1106
  // There might be no change of state due to Container calling this API after loading runtime.
1106
1107
  const changeOfState = this._connected !== connected;
@@ -1118,7 +1119,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1118
1119
  this._perfSignalData.trackingSignalSequenceNumber = undefined;
1119
1120
  }
1120
1121
  else {
1121
- (0, common_utils_1.assert)(this.attachState === container_definitions_1.AttachState.Attached, 0x3cd /* Connection is possible only if container exists in storage */);
1122
+ (0, core_utils_1.assert)(this.attachState === container_definitions_1.AttachState.Attached, 0x3cd /* Connection is possible only if container exists in storage */);
1122
1123
  }
1123
1124
  // Fail while disconnected
1124
1125
  if (reconnection) {
@@ -1213,7 +1214,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1213
1214
  this.blobManager.processBlobAttachOp(message, local);
1214
1215
  break;
1215
1216
  case ContainerMessageType.IdAllocation:
1216
- (0, common_utils_1.assert)(this.idCompressor !== undefined, 0x67c /* IdCompressor should be defined if enabled */);
1217
+ (0, core_utils_1.assert)(this.idCompressor !== undefined, 0x67c /* IdCompressor should be defined if enabled */);
1217
1218
  this.idCompressor.finalizeCreationRange(message.contents);
1218
1219
  break;
1219
1220
  case ContainerMessageType.ChunkedOp:
@@ -1311,7 +1312,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1311
1312
  await this.dataStores.waitIfPendingAlias(id);
1312
1313
  const internalId = this.internalId(id);
1313
1314
  const context = await this.dataStores.getDataStore(internalId, { wait });
1314
- (0, common_utils_1.assert)(await context.isRoot(), 0x12b /* "did not get root data store" */);
1315
+ (0, core_utils_1.assert)(await context.isRoot(), 0x12b /* "did not get root data store" */);
1315
1316
  return context.realize();
1316
1317
  }
1317
1318
  /**
@@ -1319,9 +1320,9 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1319
1320
  * This method is expected to be called at the end of a batch.
1320
1321
  */
1321
1322
  flush() {
1322
- (0, common_utils_1.assert)(this._orderSequentiallyCalls === 0, 0x24c /* "Cannot call `flush()` from `orderSequentially`'s callback" */);
1323
+ (0, core_utils_1.assert)(this._orderSequentiallyCalls === 0, 0x24c /* "Cannot call `flush()` from `orderSequentially`'s callback" */);
1323
1324
  this.outbox.flush();
1324
- (0, common_utils_1.assert)(this.outbox.isEmpty, 0x3cf /* reentrancy */);
1325
+ (0, core_utils_1.assert)(this.outbox.isEmpty, 0x3cf /* reentrancy */);
1325
1326
  }
1326
1327
  orderSequentially(callback) {
1327
1328
  let checkpoint;
@@ -1481,10 +1482,10 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1481
1482
  }
1482
1483
  setAttachState(attachState) {
1483
1484
  if (attachState === container_definitions_1.AttachState.Attaching) {
1484
- (0, common_utils_1.assert)(this.attachState === container_definitions_1.AttachState.Attaching, 0x12d /* "Container Context should already be in attaching state" */);
1485
+ (0, core_utils_1.assert)(this.attachState === container_definitions_1.AttachState.Attaching, 0x12d /* "Container Context should already be in attaching state" */);
1485
1486
  }
1486
1487
  else {
1487
- (0, common_utils_1.assert)(this.attachState === container_definitions_1.AttachState.Attached, 0x12e /* "Container Context should already be in attached state" */);
1488
+ (0, core_utils_1.assert)(this.attachState === container_definitions_1.AttachState.Attached, 0x12e /* "Container Context should already be in attached state" */);
1488
1489
  this.emit("attached");
1489
1490
  }
1490
1491
  if (attachState === container_definitions_1.AttachState.Attached && !this.hasPendingMessages()) {
@@ -1542,7 +1543,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1542
1543
  await this.collectGarbage({ logger: summaryLogger, runSweep, fullGC }, telemetryContext);
1543
1544
  }
1544
1545
  const { stats, summary } = await this.summarizerNode.summarize(fullTree, trackState, telemetryContext);
1545
- (0, common_utils_1.assert)(summary.type === protocol_definitions_1.SummaryType.Tree, 0x12f /* "Container Runtime's summarize should always return a tree" */);
1546
+ (0, core_utils_1.assert)(summary.type === protocol_definitions_1.SummaryType.Tree, 0x12f /* "Container Runtime's summarize should always return a tree" */);
1546
1547
  return { stats, summary };
1547
1548
  }
1548
1549
  finally {
@@ -1654,7 +1655,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1654
1655
  case gc_1.GCNodeType.SubDataStore:
1655
1656
  return this.dataStores.getDataStorePackagePath(nodePath);
1656
1657
  default:
1657
- (0, common_utils_1.assert)(false, 0x2de /* "Package path requested for unsupported node type." */);
1658
+ (0, core_utils_1.assert)(false, 0x2de /* "Package path requested for unsupported node type." */);
1658
1659
  }
1659
1660
  }
1660
1661
  /**
@@ -1721,7 +1722,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1721
1722
  all: { summaryNumber },
1722
1723
  },
1723
1724
  });
1724
- (0, common_utils_1.assert)(this.outbox.isEmpty, 0x3d1 /* Can't trigger summary in the middle of a batch */);
1725
+ (0, core_utils_1.assert)(this.outbox.isEmpty, 0x3d1 /* Can't trigger summary in the middle of a batch */);
1725
1726
  let latestSnapshotVersionId;
1726
1727
  if (refreshLatestAck) {
1727
1728
  const latestSnapshotInfo = await this.refreshLatestSummaryAckFromServer((0, telemetry_utils_1.createChildLogger)({
@@ -1733,6 +1734,40 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1733
1734
  // We might need to catch up to the latest summary's reference sequence number before pausing.
1734
1735
  await this.waitForDeltaManagerToCatchup(latestSnapshotRefSeq, summaryNumberLogger);
1735
1736
  }
1737
+ // If there are pending (unacked ops), the summary will not be eventual consistent and it may even be
1738
+ // incorrect. So, wait for the container to be saved with a timeout. If the container is not saved
1739
+ // within the timeout, check if it should be failed or can continue.
1740
+ if (this.validateSummaryBeforeUpload && this.hasPendingMessages()) {
1741
+ const countBefore = this.pendingMessagesCount;
1742
+ // The timeout for waiting for pending ops can be overridden via configurations.
1743
+ const pendingOpsTimeout = this.mc.config.getNumber("Fluid.Summarizer.waitForPendingOpsTimeoutMs") ??
1744
+ exports.defaultPendingOpsWaitTimeoutMs;
1745
+ await new Promise((resolve, reject) => {
1746
+ const timeoutId = setTimeout(() => resolve(), pendingOpsTimeout);
1747
+ this.once("saved", () => {
1748
+ clearTimeout(timeoutId);
1749
+ resolve();
1750
+ });
1751
+ this.once("dispose", () => {
1752
+ clearTimeout(timeoutId);
1753
+ reject(new Error("Runtime is disposed while summarizing"));
1754
+ });
1755
+ });
1756
+ // Log that there are pending ops while summarizing. This will help us gather data on how often this
1757
+ // happens, whether we attempted to wait for these ops to be acked and what was the result.
1758
+ summaryNumberLogger.sendTelemetryEvent({
1759
+ eventName: "PendingOpsWhileSummarizing",
1760
+ saved: this.hasPendingMessages() ? false : true,
1761
+ timeout: pendingOpsTimeout,
1762
+ countBefore,
1763
+ countAfter: this.pendingMessagesCount,
1764
+ });
1765
+ // There could still be pending ops. Check if summary should fail or continue.
1766
+ const pendingMessagesFailResult = await this.shouldFailSummaryOnPendingOps(summaryNumberLogger, this.deltaManager.lastSequenceNumber, this.deltaManager.minimumSequenceNumber, finalAttempt, true /* beforeSummaryGeneration */);
1767
+ if (pendingMessagesFailResult !== undefined) {
1768
+ return pendingMessagesFailResult;
1769
+ }
1770
+ }
1736
1771
  const shouldPauseInboundSignal = this.mc.config.getBoolean("Fluid.ContainerRuntime.SubmitSummary.disableInboundSignalPause") !== true;
1737
1772
  let summaryRefSeqNum;
1738
1773
  try {
@@ -1759,7 +1794,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1759
1794
  // That said, we rely on submitSystemMessage() that today only works in connected state.
1760
1795
  // So if we fail here, it either means that RunWhileConnectedCoordinator does not work correctly,
1761
1796
  // OR that design changed and we need to remove this check and fix submitSystemMessage.
1762
- (0, common_utils_1.assert)(this.connected, 0x258 /* "connected" */);
1797
+ (0, core_utils_1.assert)(this.connected, 0x258 /* "connected" */);
1763
1798
  // Ensure that lastSequenceNumber has not changed after pausing.
1764
1799
  // We need the summary op's reference sequence number to match our summary sequence number,
1765
1800
  // otherwise we'll get the wrong sequence number stamped on the summary's .protocol attributes.
@@ -1769,7 +1804,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1769
1804
  error: `lastSequenceNumber changed before uploading to storage. ${this.deltaManager.lastSequenceNumber} !== ${summaryRefSeqNum}`,
1770
1805
  };
1771
1806
  }
1772
- (0, common_utils_1.assert)(summaryRefSeqNum === this.deltaManager.lastMessage?.sequenceNumber, 0x395 /* it's one and the same thing */);
1807
+ (0, core_utils_1.assert)(summaryRefSeqNum === this.deltaManager.lastMessage?.sequenceNumber, 0x395 /* it's one and the same thing */);
1773
1808
  if (lastAck !== this.summaryCollection.latestAck) {
1774
1809
  return {
1775
1810
  continue: false,
@@ -1787,7 +1822,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1787
1822
  error: continueResult.error,
1788
1823
  };
1789
1824
  }
1790
- const trace = common_utils_1.Trace.start();
1825
+ const trace = client_utils_1.Trace.start();
1791
1826
  let summarizeResult;
1792
1827
  // If the GC state needs to be reset, we need to force a full tree summary and update the unreferenced
1793
1828
  // state of all the nodes.
@@ -1822,33 +1857,9 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1822
1857
  error,
1823
1858
  };
1824
1859
  }
1825
- // If there are pending messages, the summary has more data than at the summaryRefSeqNum.
1826
- if (this.hasPendingMessages()) {
1827
- // If "SkipFailingIncorrectSummary" option is true, don't fail the summary in the last attempt.
1828
- // This is a fallback to make progress in documents where there are consistently pending ops in
1829
- // the summarizer.
1830
- if (finalAttempt &&
1831
- this.mc.config.getBoolean("Fluid.Summarizer.SkipFailingIncorrectSummary")) {
1832
- const error = telemetry_utils_1.DataProcessingError.create("Pending ops during summarization", "submitSummary", undefined, { pendingMessages: this.pendingMessagesCount });
1833
- summaryNumberLogger.sendErrorEvent({
1834
- eventName: "SkipFailingIncorrectSummary",
1835
- referenceSequenceNumber: summaryRefSeqNum,
1836
- minimumSequenceNumber,
1837
- }, error);
1838
- }
1839
- else {
1840
- // Default retry delay is 1 second. This can be overridden via config so that we can adjust it
1841
- // based on telemetry while we decide on a stable number.
1842
- const retryDelayMs = this.mc.config.getNumber("Fluid.Summarizer.PendingOpsRetryDelayMs") ??
1843
- 1000;
1844
- const error = new summary_1.RetriableSummaryError("PendingMessagesInSummary", retryDelayMs / 1000, { count: this.pendingMessagesCount });
1845
- return {
1846
- stage: "base",
1847
- referenceSequenceNumber: summaryRefSeqNum,
1848
- minimumSequenceNumber,
1849
- error,
1850
- };
1851
- }
1860
+ const pendingMessagesFailResult = await this.shouldFailSummaryOnPendingOps(summaryNumberLogger, summaryRefSeqNum, minimumSequenceNumber, finalAttempt, false /* beforeSummaryGeneration */);
1861
+ if (pendingMessagesFailResult !== undefined) {
1862
+ return pendingMessagesFailResult;
1852
1863
  }
1853
1864
  }
1854
1865
  const { summary: summaryTree, stats: partialStats } = summarizeResult;
@@ -1858,7 +1869,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1858
1869
  // Because handles are unchanged dataStores in the current logic,
1859
1870
  // summarized dataStore count is total dataStore count minus handle count
1860
1871
  const dataStoreTree = summaryTree.tree[runtime_definitions_1.channelsTreeName];
1861
- (0, common_utils_1.assert)(dataStoreTree.type === protocol_definitions_1.SummaryType.Tree, 0x1fc /* "summary is not a tree" */);
1872
+ (0, core_utils_1.assert)(dataStoreTree.type === protocol_definitions_1.SummaryType.Tree, 0x1fc /* "summary is not a tree" */);
1862
1873
  const handleCount = Object.values(dataStoreTree.tree).filter((value) => value.type === protocol_definitions_1.SummaryType.Handle).length;
1863
1874
  const gcSummaryTreeStats = summaryTree.tree[runtime_definitions_1.gcTreeKey]
1864
1875
  ? (0, runtime_utils_1.calculateStats)(summaryTree.tree[runtime_definitions_1.gcTreeKey])
@@ -1970,6 +1981,50 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1970
1981
  }
1971
1982
  }
1972
1983
  }
1984
+ /**
1985
+ * This helper is called during summarization. If there are pending ops, it will return a failed summarize result
1986
+ * (IBaseSummarizeResult) unless this is the final summarize attempt and SkipFailingIncorrectSummary option is set.
1987
+ * @param logger - The logger to be used for sending telemetry.
1988
+ * @param referenceSequenceNumber - The reference sequence number of the summary attempt.
1989
+ * @param minimumSequenceNumber - The minimum sequence number of the summary attempt.
1990
+ * @param finalAttempt - Whether this is the final summary attempt.
1991
+ * @param beforeSummaryGeneration - Whether this is called before summary generation or after.
1992
+ * @returns failed summarize result (IBaseSummarizeResult) if summary should be failed, undefined otherwise.
1993
+ */
1994
+ async shouldFailSummaryOnPendingOps(logger, referenceSequenceNumber, minimumSequenceNumber, finalAttempt, beforeSummaryGeneration) {
1995
+ if (!this.hasPendingMessages()) {
1996
+ return;
1997
+ }
1998
+ // If "SkipFailingIncorrectSummary" option is true, don't fail the summary in the last attempt.
1999
+ // This is a fallback to make progress in documents where there are consistently pending ops in
2000
+ // the summarizer.
2001
+ if (finalAttempt &&
2002
+ this.mc.config.getBoolean("Fluid.Summarizer.SkipFailingIncorrectSummary")) {
2003
+ const error = telemetry_utils_1.DataProcessingError.create("Pending ops during summarization", "submitSummary", undefined, { pendingMessages: this.pendingMessagesCount });
2004
+ logger.sendErrorEvent({
2005
+ eventName: "SkipFailingIncorrectSummary",
2006
+ referenceSequenceNumber,
2007
+ minimumSequenceNumber,
2008
+ beforeGenerate: beforeSummaryGeneration,
2009
+ }, error);
2010
+ }
2011
+ else {
2012
+ // The retry delay when there are pending ops can be overridden via config so that we can adjust it
2013
+ // based on telemetry while we decide on a stable number.
2014
+ const retryDelayMs = this.mc.config.getNumber("Fluid.Summarizer.PendingOpsRetryDelayMs") ??
2015
+ exports.defaultPendingOpsRetryDelayMs;
2016
+ const error = new summary_1.RetriableSummaryError("PendingOpsWhileSummarizing", retryDelayMs / 1000, {
2017
+ count: this.pendingMessagesCount,
2018
+ beforeGenerate: beforeSummaryGeneration,
2019
+ });
2020
+ return {
2021
+ stage: "base",
2022
+ referenceSequenceNumber,
2023
+ minimumSequenceNumber,
2024
+ error,
2025
+ };
2026
+ }
2027
+ }
1973
2028
  get pendingMessagesCount() {
1974
2029
  return this.pendingStateManager.pendingMessagesCount + this.outbox.messageCount;
1975
2030
  }
@@ -1978,11 +2033,11 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1978
2033
  }
1979
2034
  updateDocumentDirtyState(dirty) {
1980
2035
  if (this.attachState !== container_definitions_1.AttachState.Attached) {
1981
- (0, common_utils_1.assert)(dirty, 0x3d2 /* Non-attached container is dirty */);
2036
+ (0, core_utils_1.assert)(dirty, 0x3d2 /* Non-attached container is dirty */);
1982
2037
  }
1983
2038
  else {
1984
2039
  // Other way is not true = see this.isContainerMessageDirtyable()
1985
- (0, common_utils_1.assert)(!dirty || this.hasPendingMessages(), 0x3d3 /* if doc is dirty, there has to be pending ops */);
2040
+ (0, core_utils_1.assert)(!dirty || this.hasPendingMessages(), 0x3d3 /* if doc is dirty, there has to be pending ops */);
1986
2041
  }
1987
2042
  if (this.dirtyContainer === dirty) {
1988
2043
  return;
@@ -2015,7 +2070,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
2015
2070
  let idAllocationBatchMessage;
2016
2071
  let idRange;
2017
2072
  if (this.idCompressorEnabled) {
2018
- (0, common_utils_1.assert)(this.idCompressor !== undefined, 0x67d /* IdCompressor should be defined if enabled */);
2073
+ (0, core_utils_1.assert)(this.idCompressor !== undefined, 0x67d /* IdCompressor should be defined if enabled */);
2019
2074
  idRange = this.idCompressor.takeNextCreationRange();
2020
2075
  // Don't include the idRange if there weren't any Ids allocated
2021
2076
  idRange = idRange?.ids !== undefined ? idRange : undefined;
@@ -2042,7 +2097,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
2042
2097
  this.verifyNotClosed();
2043
2098
  this.verifyCanSubmitOps();
2044
2099
  // There should be no ops in detached container state!
2045
- (0, common_utils_1.assert)(this.attachState !== container_definitions_1.AttachState.Detached, 0x132 /* "sending ops in detached container" */);
2100
+ (0, core_utils_1.assert)(this.attachState !== container_definitions_1.AttachState.Detached, 0x132 /* "sending ops in detached container" */);
2046
2101
  const serializedContent = JSON.stringify(containerRuntimeMessage);
2047
2102
  // Note that the real (non-proxy) delta manager is used here to get the readonly info. This is because
2048
2103
  // container runtime's ability to submit ops depend on the actual readonly state of the delta manager.
@@ -2142,15 +2197,15 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
2142
2197
  setTimeout(flush, 0);
2143
2198
  break;
2144
2199
  default:
2145
- (0, common_utils_1.assert)(this._orderSequentiallyCalls > 0, 0x587 /* Unreachable unless running under orderSequentially */);
2200
+ (0, core_utils_1.assert)(this._orderSequentiallyCalls > 0, 0x587 /* Unreachable unless running under orderSequentially */);
2146
2201
  break;
2147
2202
  }
2148
2203
  }
2149
2204
  submitSummaryMessage(contents, referenceSequenceNumber) {
2150
2205
  this.verifyNotClosed();
2151
- (0, common_utils_1.assert)(this.connected, 0x133 /* "Container disconnected when trying to submit system message" */);
2206
+ (0, core_utils_1.assert)(this.connected, 0x133 /* "Container disconnected when trying to submit system message" */);
2152
2207
  // System message should not be sent in the middle of the batch.
2153
- (0, common_utils_1.assert)(this.outbox.isEmpty, 0x3d4 /* System op in the middle of a batch */);
2208
+ (0, core_utils_1.assert)(this.outbox.isEmpty, 0x3d4 /* System op in the middle of a batch */);
2154
2209
  // back-compat: ADO #1385: Make this call unconditional in the future
2155
2210
  return this.submitSummaryFn !== undefined
2156
2211
  ? this.submitSummaryFn(contents, referenceSequenceNumber)
@@ -2288,29 +2343,22 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
2288
2343
  /** Implementation of ISummarizerInternalsProvider.refreshLatestSummaryAck */
2289
2344
  async refreshLatestSummaryAck(options) {
2290
2345
  const { proposalHandle, ackHandle, summaryRefSeq, summaryLogger } = options;
2346
+ // proposalHandle is always passed from RunningSummarizer.
2347
+ (0, core_utils_1.assert)(proposalHandle !== undefined, 0x766 /* proposalHandle should be available */);
2291
2348
  const readAndParseBlob = async (id) => (0, driver_utils_1.readAndParse)(this.storage, id);
2292
- // The call to fetch the snapshot is very expensive and not always needed.
2293
- // It should only be done by the summarizerNode, if required.
2294
- // When fetching from storage we will always get the latest version and do not use the ackHandle.
2295
- const fetchLatestSnapshot = async () => {
2296
- let fetchResult = await this.fetchSnapshotFromStorageAndMaybeClose(summaryLogger, {
2349
+ const result = await this.summarizerNode.refreshLatestSummary(proposalHandle, summaryRefSeq);
2350
+ /**
2351
+ * When refreshing a summary ack, this check indicates a new ack of a summary that is newer than the
2352
+ * current summary that is tracked, but this summarizer runtime did not produce/track that summary. Thus
2353
+ * it needs to refresh its state. Today refresh is done by fetching the latest snapshot to update the cache
2354
+ * and then close as the current main client is likely to be re-elected as the parent summarizer again.
2355
+ */
2356
+ if (!result.isSummaryTracked && result.isSummaryNewer) {
2357
+ const fetchResult = await this.fetchSnapshotFromStorage(summaryLogger, {
2297
2358
  eventName: "RefreshLatestSummaryAckFetch",
2298
2359
  ackHandle,
2299
2360
  targetSequenceNumber: summaryRefSeq,
2300
2361
  }, readAndParseBlob, null);
2301
- /**
2302
- * back-compat - Older loaders and drivers (pre 2.0.0-internal.1.4) don't have fetchSource as a param in the
2303
- * getVersions API. So, they will not fetch the latest snapshot from network in the previous fetch call. For
2304
- * these scenarios, fetch the snapshot corresponding to the ack handle to have the same behavior before the
2305
- * change that started fetching latest snapshot always.
2306
- */
2307
- if (fetchResult.latestSnapshotRefSeq < summaryRefSeq) {
2308
- fetchResult = await this.fetchSnapshotFromStorageAndMaybeClose(summaryLogger, {
2309
- eventName: "RefreshLatestSummaryAckFetchBackCompat",
2310
- ackHandle,
2311
- targetSequenceNumber: summaryRefSeq,
2312
- }, readAndParseBlob, ackHandle);
2313
- }
2314
2362
  /**
2315
2363
  * If the fetched snapshot is older than the one for which the ack was received, close the container.
2316
2364
  * This should never happen because an ack should be sent after the latest summary is updated in the server.
@@ -2330,17 +2378,11 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
2330
2378
  this.disposeFn(error);
2331
2379
  throw error;
2332
2380
  }
2333
- // In case we had to retrieve the latest snapshot and it is different than summaryRefSeq,
2334
- // wait for the delta manager to catch up before refreshing the latest Summary.
2335
- await this.waitForDeltaManagerToCatchup(fetchResult.latestSnapshotRefSeq, summaryLogger);
2336
- return {
2337
- snapshotTree: fetchResult.snapshotTree,
2338
- snapshotRefSeq: fetchResult.latestSnapshotRefSeq,
2339
- };
2340
- };
2341
- const result = await this.summarizerNode.refreshLatestSummary(proposalHandle, summaryRefSeq, fetchLatestSnapshot, readAndParseBlob, summaryLogger);
2381
+ await this.closeStaleSummarizer("RefreshLatestSummaryAckFetch");
2382
+ return;
2383
+ }
2342
2384
  // Notify the garbage collector so it can update its latest summary state.
2343
- await this.garbageCollector.refreshLatestSummary(proposalHandle, result, readAndParseBlob);
2385
+ await this.garbageCollector.refreshLatestSummary(result);
2344
2386
  }
2345
2387
  /**
2346
2388
  * Fetches the latest snapshot from storage and uses it to refresh SummarizerNode's
@@ -2350,32 +2392,38 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
2350
2392
  */
2351
2393
  async refreshLatestSummaryAckFromServer(summaryLogger) {
2352
2394
  const readAndParseBlob = async (id) => (0, driver_utils_1.readAndParse)(this.storage, id);
2353
- const { snapshotTree, versionId, latestSnapshotRefSeq } = await this.fetchSnapshotFromStorageAndMaybeClose(summaryLogger, {
2395
+ const { versionId, latestSnapshotRefSeq } = await this.fetchSnapshotFromStorage(summaryLogger, {
2354
2396
  eventName: "RefreshLatestSummaryFromServerFetch",
2355
2397
  }, readAndParseBlob, null);
2356
- const fetchLatestSnapshot = {
2357
- snapshotTree,
2358
- snapshotRefSeq: latestSnapshotRefSeq,
2359
- };
2360
- const result = await this.summarizerNode.refreshLatestSummary(undefined /* proposalHandle */, latestSnapshotRefSeq, async () => fetchLatestSnapshot, readAndParseBlob, summaryLogger);
2361
- // Notify the garbage collector so it can update its latest summary state.
2362
- await this.garbageCollector.refreshLatestSummary(undefined /* proposalHandle */, result, readAndParseBlob);
2398
+ await this.closeStaleSummarizer("RefreshLatestSummaryFromServerFetch");
2363
2399
  return { latestSnapshotRefSeq, latestSnapshotVersionId: versionId };
2364
2400
  }
2401
+ async closeStaleSummarizer(codePath) {
2402
+ this.mc.logger.sendTelemetryEvent({
2403
+ eventName: "ClosingSummarizerOnSummaryStale",
2404
+ codePath,
2405
+ message: "Stopping fetch from storage",
2406
+ closeSummarizerDelayMs: this.closeSummarizerDelayMs,
2407
+ }, new telemetry_utils_1.GenericError("Restarting summarizer instead of refreshing"));
2408
+ // Delay before restarting summarizer to prevent the summarizer from restarting too frequently.
2409
+ await (0, core_utils_1.delay)(this.closeSummarizerDelayMs);
2410
+ this._summarizer?.stop("latestSummaryStateStale");
2411
+ this.disposeFn();
2412
+ }
2365
2413
  /**
2366
2414
  * Downloads snapshot from storage with the given versionId or latest if versionId is null.
2367
2415
  * By default, it also closes the container after downloading the snapshot. However, this may be
2368
2416
  * overridden via options.
2369
2417
  */
2370
- async fetchSnapshotFromStorageAndMaybeClose(logger, event, readAndParseBlob, versionId) {
2371
- const snapshotResults = await telemetry_utils_1.PerformanceEvent.timedExecAsync(logger, event, async (perfEvent) => {
2418
+ async fetchSnapshotFromStorage(logger, event, readAndParseBlob, versionId) {
2419
+ return telemetry_utils_1.PerformanceEvent.timedExecAsync(logger, event, async (perfEvent) => {
2372
2420
  const stats = {};
2373
- const trace = common_utils_1.Trace.start();
2421
+ const trace = client_utils_1.Trace.start();
2374
2422
  const versions = await this.storage.getVersions(versionId, 1, "refreshLatestSummaryAckFromServer", versionId === null ? driver_definitions_1.FetchSource.noCache : undefined);
2375
- (0, common_utils_1.assert)(!!versions && !!versions[0], 0x137 /* "Failed to get version from storage" */);
2423
+ (0, core_utils_1.assert)(!!versions && !!versions[0], 0x137 /* "Failed to get version from storage" */);
2376
2424
  stats.getVersionDuration = trace.trace().duration;
2377
2425
  const maybeSnapshot = await this.storage.getSnapshotTree(versions[0]);
2378
- (0, common_utils_1.assert)(!!maybeSnapshot, 0x138 /* "Failed to get snapshot from storage" */);
2426
+ (0, core_utils_1.assert)(!!maybeSnapshot, 0x138 /* "Failed to get snapshot from storage" */);
2379
2427
  stats.getSnapshotDuration = trace.trace().duration;
2380
2428
  const latestSnapshotRefSeq = await (0, runtime_utils_1.seqFromTree)(maybeSnapshot, readAndParseBlob);
2381
2429
  stats.snapshotRefSeq = latestSnapshotRefSeq;
@@ -2387,45 +2435,37 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
2387
2435
  latestSnapshotRefSeq,
2388
2436
  };
2389
2437
  });
2390
- // We choose to close the summarizer after the snapshot cache is updated to avoid
2391
- // situations which the main client (which is likely to be re-elected as the leader again)
2392
- // loads the summarizer from cache.
2393
- if (this.summaryStateUpdateMethod !== "refreshFromSnapshot") {
2394
- this.mc.logger.sendTelemetryEvent({
2395
- ...event,
2396
- eventName: "ClosingSummarizerOnSummaryStale",
2397
- codePath: event.eventName,
2398
- message: "Stopping fetch from storage",
2399
- versionId: versionId != null ? versionId : undefined,
2400
- closeSummarizerDelayMs: this.closeSummarizerDelayMs,
2401
- }, new telemetry_utils_1.GenericError("Restarting summarizer instead of refreshing"));
2402
- // Delay before restarting summarizer to prevent the summarizer from restarting too frequently.
2403
- await (0, common_utils_1.delay)(this.closeSummarizerDelayMs);
2404
- this._summarizer?.stop("latestSummaryStateStale");
2405
- this.disposeFn();
2406
- }
2407
- return snapshotResults;
2408
2438
  }
2409
2439
  notifyAttaching() { } // do nothing (deprecated method)
2410
2440
  async getPendingLocalState(props) {
2411
- this.verifyNotClosed();
2412
- const waitBlobsToAttach = props?.notifyImminentClosure;
2413
- if (this._orderSequentiallyCalls !== 0) {
2414
- throw new telemetry_utils_1.UsageError("can't get state during orderSequentially");
2415
- }
2416
- const pendingAttachmentBlobs = await this.blobManager.getPendingBlobs(waitBlobsToAttach);
2417
- if (!pendingAttachmentBlobs && !this.hasPendingMessages()) {
2418
- return; // no pending state to save
2419
- }
2420
- // Flush pending batch.
2421
- // getPendingLocalState() is only exposed through Container.closeAndGetPendingLocalState(), so it's safe
2422
- // to close current batch.
2423
- this.flush();
2424
- const pendingState = {
2425
- pending: this.pendingStateManager.getLocalState(),
2426
- pendingAttachmentBlobs,
2427
- };
2428
- return pendingState;
2441
+ return telemetry_utils_1.PerformanceEvent.timedExecAsync(this.mc.logger, {
2442
+ eventName: "getPendingLocalState",
2443
+ notifyImminentClosure: props?.notifyImminentClosure,
2444
+ }, async (event) => {
2445
+ this.verifyNotClosed();
2446
+ const waitBlobsToAttach = props?.notifyImminentClosure;
2447
+ if (this._orderSequentiallyCalls !== 0) {
2448
+ throw new telemetry_utils_1.UsageError("can't get state during orderSequentially");
2449
+ }
2450
+ const pendingAttachmentBlobs = await this.blobManager.getPendingBlobs(waitBlobsToAttach);
2451
+ const pending = this.pendingStateManager.getLocalState();
2452
+ if (!pendingAttachmentBlobs && !this.hasPendingMessages()) {
2453
+ return; // no pending state to save
2454
+ }
2455
+ // Flush pending batch.
2456
+ // getPendingLocalState() is only exposed through Container.closeAndGetPendingLocalState(), so it's safe
2457
+ // to close current batch.
2458
+ this.flush();
2459
+ const pendingState = {
2460
+ pending,
2461
+ pendingAttachmentBlobs,
2462
+ };
2463
+ event.end({
2464
+ attachmentBlobsSize: Object.keys(pendingAttachmentBlobs ?? {}).length,
2465
+ pendingOpsSize: pending?.pendingStates.length,
2466
+ });
2467
+ return pendingState;
2468
+ });
2429
2469
  }
2430
2470
  summarizeOnDemand(options) {
2431
2471
  if (this.isSummarizerClient) {