@fluidframework/container-runtime 2.23.0 → 2.31.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 (317) hide show
  1. package/CHANGELOG.md +593 -537
  2. package/api-report/container-runtime.legacy.alpha.api.md +0 -246
  3. package/dist/blobManager/blobManager.d.ts +11 -9
  4. package/dist/blobManager/blobManager.d.ts.map +1 -1
  5. package/dist/blobManager/blobManager.js +38 -39
  6. package/dist/blobManager/blobManager.js.map +1 -1
  7. package/dist/blobManager/blobManagerSnapSum.d.ts +2 -4
  8. package/dist/blobManager/blobManagerSnapSum.d.ts.map +1 -1
  9. package/dist/blobManager/blobManagerSnapSum.js +6 -6
  10. package/dist/blobManager/blobManagerSnapSum.js.map +1 -1
  11. package/dist/channelCollection.d.ts +1 -7
  12. package/dist/channelCollection.d.ts.map +1 -1
  13. package/dist/channelCollection.js +2 -27
  14. package/dist/channelCollection.js.map +1 -1
  15. package/dist/connectionTelemetry.d.ts +0 -43
  16. package/dist/connectionTelemetry.d.ts.map +1 -1
  17. package/dist/connectionTelemetry.js.map +1 -1
  18. package/dist/containerRuntime.d.ts +40 -145
  19. package/dist/containerRuntime.d.ts.map +1 -1
  20. package/dist/containerRuntime.js +149 -364
  21. package/dist/containerRuntime.js.map +1 -1
  22. package/dist/dataStoreContext.d.ts +6 -14
  23. package/dist/dataStoreContext.d.ts.map +1 -1
  24. package/dist/dataStoreContext.js +14 -26
  25. package/dist/dataStoreContext.js.map +1 -1
  26. package/dist/gc/garbageCollection.d.ts.map +1 -1
  27. package/dist/gc/garbageCollection.js +2 -20
  28. package/dist/gc/garbageCollection.js.map +1 -1
  29. package/dist/gc/gcConfigs.d.ts.map +1 -1
  30. package/dist/gc/gcConfigs.js +0 -2
  31. package/dist/gc/gcConfigs.js.map +1 -1
  32. package/dist/gc/gcDefinitions.d.ts +8 -24
  33. package/dist/gc/gcDefinitions.d.ts.map +1 -1
  34. package/dist/gc/gcDefinitions.js +1 -3
  35. package/dist/gc/gcDefinitions.js.map +1 -1
  36. package/dist/gc/gcHelpers.d.ts.map +1 -1
  37. package/dist/gc/gcHelpers.js +1 -4
  38. package/dist/gc/gcHelpers.js.map +1 -1
  39. package/dist/gc/gcSummaryStateTracker.d.ts.map +1 -1
  40. package/dist/gc/gcSummaryStateTracker.js +0 -1
  41. package/dist/gc/gcSummaryStateTracker.js.map +1 -1
  42. package/dist/gc/gcTelemetry.d.ts.map +1 -1
  43. package/dist/gc/gcTelemetry.js +6 -18
  44. package/dist/gc/gcTelemetry.js.map +1 -1
  45. package/dist/index.d.ts +2 -2
  46. package/dist/index.d.ts.map +1 -1
  47. package/dist/index.js +2 -2
  48. package/dist/index.js.map +1 -1
  49. package/dist/legacy.d.ts +0 -29
  50. package/dist/messageTypes.d.ts.map +1 -1
  51. package/dist/messageTypes.js.map +1 -1
  52. package/dist/opLifecycle/batchManager.d.ts.map +1 -1
  53. package/dist/opLifecycle/batchManager.js +16 -5
  54. package/dist/opLifecycle/batchManager.js.map +1 -1
  55. package/dist/opLifecycle/outbox.d.ts +12 -3
  56. package/dist/opLifecycle/outbox.d.ts.map +1 -1
  57. package/dist/opLifecycle/outbox.js +41 -21
  58. package/dist/opLifecycle/outbox.js.map +1 -1
  59. package/dist/packageVersion.d.ts +1 -1
  60. package/dist/packageVersion.js +1 -1
  61. package/dist/packageVersion.js.map +1 -1
  62. package/dist/pendingStateManager.d.ts +1 -0
  63. package/dist/pendingStateManager.d.ts.map +1 -1
  64. package/dist/pendingStateManager.js +12 -2
  65. package/dist/pendingStateManager.js.map +1 -1
  66. package/dist/runCounter.d.ts +11 -0
  67. package/dist/runCounter.d.ts.map +1 -0
  68. package/dist/runCounter.js +43 -0
  69. package/dist/runCounter.js.map +1 -0
  70. package/dist/runtimeLayerCompatState.d.ts +51 -0
  71. package/dist/runtimeLayerCompatState.d.ts.map +1 -0
  72. package/dist/runtimeLayerCompatState.js +123 -0
  73. package/dist/runtimeLayerCompatState.js.map +1 -0
  74. package/dist/signalTelemetryProcessing.d.ts +33 -0
  75. package/dist/signalTelemetryProcessing.d.ts.map +1 -0
  76. package/dist/signalTelemetryProcessing.js +149 -0
  77. package/dist/signalTelemetryProcessing.js.map +1 -0
  78. package/dist/summary/documentSchema.d.ts +7 -31
  79. package/dist/summary/documentSchema.d.ts.map +1 -1
  80. package/dist/summary/documentSchema.js +2 -18
  81. package/dist/summary/documentSchema.js.map +1 -1
  82. package/dist/summary/index.d.ts +2 -1
  83. package/dist/summary/index.d.ts.map +1 -1
  84. package/dist/summary/index.js +7 -1
  85. package/dist/summary/index.js.map +1 -1
  86. package/dist/summary/orderedClientElection.d.ts +1 -3
  87. package/dist/summary/orderedClientElection.d.ts.map +1 -1
  88. package/dist/summary/orderedClientElection.js.map +1 -1
  89. package/dist/summary/runWhileConnectedCoordinator.d.ts +1 -3
  90. package/dist/summary/runWhileConnectedCoordinator.d.ts.map +1 -1
  91. package/dist/summary/runWhileConnectedCoordinator.js +2 -7
  92. package/dist/summary/runWhileConnectedCoordinator.js.map +1 -1
  93. package/dist/summary/runningSummarizer.d.ts +1 -2
  94. package/dist/summary/runningSummarizer.d.ts.map +1 -1
  95. package/dist/summary/runningSummarizer.js +4 -23
  96. package/dist/summary/runningSummarizer.js.map +1 -1
  97. package/dist/summary/summarizer.d.ts +2 -5
  98. package/dist/summary/summarizer.d.ts.map +1 -1
  99. package/dist/summary/summarizer.js +3 -11
  100. package/dist/summary/summarizer.js.map +1 -1
  101. package/dist/summary/summarizerClientElection.d.ts.map +1 -1
  102. package/dist/summary/summarizerClientElection.js +0 -1
  103. package/dist/summary/summarizerClientElection.js.map +1 -1
  104. package/dist/summary/summarizerHeuristics.d.ts +1 -1
  105. package/dist/summary/summarizerHeuristics.d.ts.map +1 -1
  106. package/dist/summary/summarizerHeuristics.js.map +1 -1
  107. package/dist/summary/summarizerNode/summarizerNode.d.ts +2 -2
  108. package/dist/summary/summarizerNode/summarizerNode.d.ts.map +1 -1
  109. package/dist/summary/summarizerNode/summarizerNode.js +4 -4
  110. package/dist/summary/summarizerNode/summarizerNode.js.map +1 -1
  111. package/dist/summary/summarizerNode/summarizerNodeUtils.d.ts +1 -18
  112. package/dist/summary/summarizerNode/summarizerNodeUtils.d.ts.map +1 -1
  113. package/dist/summary/summarizerNode/summarizerNodeUtils.js +0 -27
  114. package/dist/summary/summarizerNode/summarizerNodeUtils.js.map +1 -1
  115. package/dist/summary/summarizerNode/summarizerNodeWithGc.d.ts +2 -2
  116. package/dist/summary/summarizerNode/summarizerNodeWithGc.d.ts.map +1 -1
  117. package/dist/summary/summarizerNode/summarizerNodeWithGc.js +1 -2
  118. package/dist/summary/summarizerNode/summarizerNodeWithGc.js.map +1 -1
  119. package/dist/summary/summarizerTypes.d.ts +109 -22
  120. package/dist/summary/summarizerTypes.d.ts.map +1 -1
  121. package/dist/summary/summarizerTypes.js.map +1 -1
  122. package/dist/summary/summaryFormat.d.ts +3 -9
  123. package/dist/summary/summaryFormat.d.ts.map +1 -1
  124. package/dist/summary/summaryFormat.js.map +1 -1
  125. package/dist/summary/summaryGenerator.d.ts.map +1 -1
  126. package/dist/summary/summaryGenerator.js +3 -9
  127. package/dist/summary/summaryGenerator.js.map +1 -1
  128. package/dist/summary/summaryHelpers.d.ts +19 -0
  129. package/dist/summary/summaryHelpers.d.ts.map +1 -0
  130. package/dist/summary/summaryHelpers.js +90 -0
  131. package/dist/summary/summaryHelpers.js.map +1 -0
  132. package/dist/summary/summaryManager.d.ts.map +1 -1
  133. package/dist/summary/summaryManager.js +0 -2
  134. package/dist/summary/summaryManager.js.map +1 -1
  135. package/lib/blobManager/blobManager.d.ts +11 -9
  136. package/lib/blobManager/blobManager.d.ts.map +1 -1
  137. package/lib/blobManager/blobManager.js +37 -37
  138. package/lib/blobManager/blobManager.js.map +1 -1
  139. package/lib/blobManager/blobManagerSnapSum.d.ts +2 -4
  140. package/lib/blobManager/blobManagerSnapSum.d.ts.map +1 -1
  141. package/lib/blobManager/blobManagerSnapSum.js +6 -6
  142. package/lib/blobManager/blobManagerSnapSum.js.map +1 -1
  143. package/lib/channelCollection.d.ts +1 -7
  144. package/lib/channelCollection.d.ts.map +1 -1
  145. package/lib/channelCollection.js +3 -30
  146. package/lib/channelCollection.js.map +1 -1
  147. package/lib/connectionTelemetry.d.ts +0 -43
  148. package/lib/connectionTelemetry.d.ts.map +1 -1
  149. package/lib/connectionTelemetry.js.map +1 -1
  150. package/lib/containerRuntime.d.ts +40 -145
  151. package/lib/containerRuntime.d.ts.map +1 -1
  152. package/lib/containerRuntime.js +151 -372
  153. package/lib/containerRuntime.js.map +1 -1
  154. package/lib/dataStoreContext.d.ts +6 -14
  155. package/lib/dataStoreContext.d.ts.map +1 -1
  156. package/lib/dataStoreContext.js +14 -26
  157. package/lib/dataStoreContext.js.map +1 -1
  158. package/lib/gc/garbageCollection.d.ts.map +1 -1
  159. package/lib/gc/garbageCollection.js +3 -23
  160. package/lib/gc/garbageCollection.js.map +1 -1
  161. package/lib/gc/gcConfigs.d.ts.map +1 -1
  162. package/lib/gc/gcConfigs.js +0 -2
  163. package/lib/gc/gcConfigs.js.map +1 -1
  164. package/lib/gc/gcDefinitions.d.ts +8 -24
  165. package/lib/gc/gcDefinitions.d.ts.map +1 -1
  166. package/lib/gc/gcDefinitions.js +1 -3
  167. package/lib/gc/gcDefinitions.js.map +1 -1
  168. package/lib/gc/gcHelpers.d.ts.map +1 -1
  169. package/lib/gc/gcHelpers.js +1 -4
  170. package/lib/gc/gcHelpers.js.map +1 -1
  171. package/lib/gc/gcSummaryStateTracker.d.ts.map +1 -1
  172. package/lib/gc/gcSummaryStateTracker.js +0 -1
  173. package/lib/gc/gcSummaryStateTracker.js.map +1 -1
  174. package/lib/gc/gcTelemetry.d.ts.map +1 -1
  175. package/lib/gc/gcTelemetry.js +7 -21
  176. package/lib/gc/gcTelemetry.js.map +1 -1
  177. package/lib/index.d.ts +2 -2
  178. package/lib/index.d.ts.map +1 -1
  179. package/lib/index.js +2 -2
  180. package/lib/index.js.map +1 -1
  181. package/lib/legacy.d.ts +0 -29
  182. package/lib/messageTypes.d.ts.map +1 -1
  183. package/lib/messageTypes.js.map +1 -1
  184. package/lib/opLifecycle/batchManager.d.ts.map +1 -1
  185. package/lib/opLifecycle/batchManager.js +16 -5
  186. package/lib/opLifecycle/batchManager.js.map +1 -1
  187. package/lib/opLifecycle/outbox.d.ts +12 -3
  188. package/lib/opLifecycle/outbox.d.ts.map +1 -1
  189. package/lib/opLifecycle/outbox.js +43 -23
  190. package/lib/opLifecycle/outbox.js.map +1 -1
  191. package/lib/packageVersion.d.ts +1 -1
  192. package/lib/packageVersion.js +1 -1
  193. package/lib/packageVersion.js.map +1 -1
  194. package/lib/pendingStateManager.d.ts +1 -0
  195. package/lib/pendingStateManager.d.ts.map +1 -1
  196. package/lib/pendingStateManager.js +12 -2
  197. package/lib/pendingStateManager.js.map +1 -1
  198. package/lib/runCounter.d.ts +11 -0
  199. package/lib/runCounter.d.ts.map +1 -0
  200. package/lib/runCounter.js +39 -0
  201. package/lib/runCounter.js.map +1 -0
  202. package/lib/runtimeLayerCompatState.d.ts +51 -0
  203. package/lib/runtimeLayerCompatState.d.ts.map +1 -0
  204. package/lib/runtimeLayerCompatState.js +118 -0
  205. package/lib/runtimeLayerCompatState.js.map +1 -0
  206. package/lib/signalTelemetryProcessing.d.ts +33 -0
  207. package/lib/signalTelemetryProcessing.d.ts.map +1 -0
  208. package/lib/signalTelemetryProcessing.js +145 -0
  209. package/lib/signalTelemetryProcessing.js.map +1 -0
  210. package/lib/summary/documentSchema.d.ts +7 -31
  211. package/lib/summary/documentSchema.d.ts.map +1 -1
  212. package/lib/summary/documentSchema.js +2 -18
  213. package/lib/summary/documentSchema.js.map +1 -1
  214. package/lib/summary/index.d.ts +2 -1
  215. package/lib/summary/index.d.ts.map +1 -1
  216. package/lib/summary/index.js +1 -0
  217. package/lib/summary/index.js.map +1 -1
  218. package/lib/summary/orderedClientElection.d.ts +1 -3
  219. package/lib/summary/orderedClientElection.d.ts.map +1 -1
  220. package/lib/summary/orderedClientElection.js.map +1 -1
  221. package/lib/summary/runWhileConnectedCoordinator.d.ts +1 -3
  222. package/lib/summary/runWhileConnectedCoordinator.d.ts.map +1 -1
  223. package/lib/summary/runWhileConnectedCoordinator.js +2 -7
  224. package/lib/summary/runWhileConnectedCoordinator.js.map +1 -1
  225. package/lib/summary/runningSummarizer.d.ts +1 -2
  226. package/lib/summary/runningSummarizer.d.ts.map +1 -1
  227. package/lib/summary/runningSummarizer.js +4 -23
  228. package/lib/summary/runningSummarizer.js.map +1 -1
  229. package/lib/summary/summarizer.d.ts +2 -5
  230. package/lib/summary/summarizer.d.ts.map +1 -1
  231. package/lib/summary/summarizer.js +3 -11
  232. package/lib/summary/summarizer.js.map +1 -1
  233. package/lib/summary/summarizerClientElection.d.ts.map +1 -1
  234. package/lib/summary/summarizerClientElection.js +0 -1
  235. package/lib/summary/summarizerClientElection.js.map +1 -1
  236. package/lib/summary/summarizerHeuristics.d.ts +1 -1
  237. package/lib/summary/summarizerHeuristics.d.ts.map +1 -1
  238. package/lib/summary/summarizerHeuristics.js.map +1 -1
  239. package/lib/summary/summarizerNode/summarizerNode.d.ts +2 -2
  240. package/lib/summary/summarizerNode/summarizerNode.d.ts.map +1 -1
  241. package/lib/summary/summarizerNode/summarizerNode.js +5 -5
  242. package/lib/summary/summarizerNode/summarizerNode.js.map +1 -1
  243. package/lib/summary/summarizerNode/summarizerNodeUtils.d.ts +1 -18
  244. package/lib/summary/summarizerNode/summarizerNodeUtils.d.ts.map +1 -1
  245. package/lib/summary/summarizerNode/summarizerNodeUtils.js +1 -25
  246. package/lib/summary/summarizerNode/summarizerNodeUtils.js.map +1 -1
  247. package/lib/summary/summarizerNode/summarizerNodeWithGc.d.ts +2 -2
  248. package/lib/summary/summarizerNode/summarizerNodeWithGc.d.ts.map +1 -1
  249. package/lib/summary/summarizerNode/summarizerNodeWithGc.js +1 -2
  250. package/lib/summary/summarizerNode/summarizerNodeWithGc.js.map +1 -1
  251. package/lib/summary/summarizerTypes.d.ts +109 -22
  252. package/lib/summary/summarizerTypes.d.ts.map +1 -1
  253. package/lib/summary/summarizerTypes.js.map +1 -1
  254. package/lib/summary/summaryFormat.d.ts +3 -9
  255. package/lib/summary/summaryFormat.d.ts.map +1 -1
  256. package/lib/summary/summaryFormat.js.map +1 -1
  257. package/lib/summary/summaryGenerator.d.ts.map +1 -1
  258. package/lib/summary/summaryGenerator.js +3 -9
  259. package/lib/summary/summaryGenerator.js.map +1 -1
  260. package/lib/summary/summaryHelpers.d.ts +19 -0
  261. package/lib/summary/summaryHelpers.d.ts.map +1 -0
  262. package/lib/summary/summaryHelpers.js +84 -0
  263. package/lib/summary/summaryHelpers.js.map +1 -0
  264. package/lib/summary/summaryManager.d.ts.map +1 -1
  265. package/lib/summary/summaryManager.js +0 -2
  266. package/lib/summary/summaryManager.js.map +1 -1
  267. package/lib/tsdoc-metadata.json +1 -1
  268. package/package.json +20 -23
  269. package/src/blobManager/blobManager.ts +70 -62
  270. package/src/blobManager/blobManagerSnapSum.ts +7 -9
  271. package/src/channelCollection.ts +4 -32
  272. package/src/connectionTelemetry.ts +0 -51
  273. package/src/containerRuntime.ts +259 -622
  274. package/src/dataStoreContext.ts +24 -33
  275. package/src/gc/{garbageCollection.md → README.md} +17 -19
  276. package/src/gc/garbageCollection.ts +9 -26
  277. package/src/gc/gcConfigs.ts +3 -6
  278. package/src/gc/gcDefinitions.ts +10 -28
  279. package/src/gc/gcHelpers.ts +0 -5
  280. package/src/gc/gcSummaryStateTracker.ts +1 -2
  281. package/src/gc/gcTelemetry.ts +8 -15
  282. package/src/index.ts +6 -6
  283. package/src/messageTypes.ts +0 -2
  284. package/src/opLifecycle/batchManager.ts +20 -6
  285. package/src/opLifecycle/outbox.ts +64 -24
  286. package/src/packageVersion.ts +1 -1
  287. package/src/pendingStateManager.ts +18 -2
  288. package/src/runCounter.ts +25 -0
  289. package/src/runtimeLayerCompatState.ts +143 -0
  290. package/src/signalTelemetryProcessing.ts +233 -0
  291. package/src/summary/documentSchema.ts +7 -38
  292. package/src/summary/index.ts +12 -0
  293. package/src/summary/orderedClientElection.ts +1 -3
  294. package/src/summary/runWhileConnectedCoordinator.ts +3 -8
  295. package/src/summary/runningSummarizer.ts +12 -20
  296. package/src/summary/summarizer.ts +6 -18
  297. package/src/summary/summarizerClientElection.ts +0 -2
  298. package/src/summary/summarizerHeuristics.ts +1 -2
  299. package/src/summary/summarizerNode/summarizerNode.ts +6 -5
  300. package/src/summary/summarizerNode/summarizerNodeUtils.ts +1 -27
  301. package/src/summary/summarizerNode/summarizerNodeWithGc.ts +2 -3
  302. package/src/summary/summarizerTypes.ts +119 -23
  303. package/src/summary/summaryFormat.ts +4 -13
  304. package/src/summary/summaryGenerator.ts +1 -8
  305. package/src/summary/summaryHelpers.ts +118 -0
  306. package/src/summary/summaryManager.ts +0 -2
  307. package/tsconfig.json +1 -0
  308. package/dist/layerCompatState.d.ts +0 -19
  309. package/dist/layerCompatState.d.ts.map +0 -1
  310. package/dist/layerCompatState.js +0 -64
  311. package/dist/layerCompatState.js.map +0 -1
  312. package/lib/layerCompatState.d.ts +0 -19
  313. package/lib/layerCompatState.d.ts.map +0 -1
  314. package/lib/layerCompatState.js +0 -60
  315. package/lib/layerCompatState.js.map +0 -1
  316. package/prettier.config.cjs +0 -8
  317. package/src/layerCompatState.ts +0 -75
@@ -3,47 +3,44 @@
3
3
  * Licensed under the MIT License.
4
4
  */
5
5
 
6
- import {
7
- Trace,
8
- TypedEventEmitter,
9
- type ILayerCompatDetails,
10
- type IProvideLayerCompatDetails,
6
+ import type {
7
+ ILayerCompatDetails,
8
+ IProvideLayerCompatDetails,
11
9
  } from "@fluid-internal/client-utils";
12
- import {
13
- AttachState,
10
+ import { Trace, TypedEventEmitter } from "@fluid-internal/client-utils";
11
+ import type {
14
12
  IAudience,
15
13
  ISelf,
16
14
  ICriticalContainerError,
17
- type IAudienceEvents,
15
+ IAudienceEvents,
18
16
  } from "@fluidframework/container-definitions";
19
- import {
17
+ import { AttachState } from "@fluidframework/container-definitions";
18
+ import type {
20
19
  IContainerContext,
21
20
  IGetPendingLocalStateProps,
22
- ILoader,
23
21
  IRuntime,
24
- LoaderHeader,
25
22
  IDeltaManager,
26
23
  IDeltaManagerFull,
27
- isIDeltaManagerFull,
28
24
  } from "@fluidframework/container-definitions/internal";
29
- import {
25
+ import { isIDeltaManagerFull } from "@fluidframework/container-definitions/internal";
26
+ import type {
30
27
  IContainerRuntime,
31
28
  IContainerRuntimeEvents,
32
29
  } from "@fluidframework/container-runtime-definitions/internal";
33
- import {
30
+ import type {
34
31
  FluidObject,
35
32
  IFluidHandle,
36
33
  IRequest,
37
34
  IResponse,
38
35
  ITelemetryBaseLogger,
39
36
  } from "@fluidframework/core-interfaces";
40
- import {
41
- type IErrorBase,
37
+ import type {
38
+ IErrorBase,
42
39
  IFluidHandleContext,
43
- type IFluidHandleInternal,
40
+ IFluidHandleInternal,
44
41
  IProvideFluidHandleContext,
42
+ ISignalEnvelope,
45
43
  } from "@fluidframework/core-interfaces/internal";
46
- import { ISignalEnvelope } from "@fluidframework/core-interfaces/internal";
47
44
  import {
48
45
  assert,
49
46
  Deferred,
@@ -51,25 +48,23 @@ import {
51
48
  PromiseCache,
52
49
  delay,
53
50
  } from "@fluidframework/core-utils/internal";
54
- import {
51
+ import type {
55
52
  IClientDetails,
56
53
  IQuorumClients,
57
54
  ISummaryTree,
58
- SummaryType,
59
55
  } from "@fluidframework/driver-definitions";
60
- import {
61
- DriverHeader,
62
- FetchSource,
56
+ import { SummaryType } from "@fluidframework/driver-definitions";
57
+ import type {
63
58
  IDocumentStorageService,
64
- type ISnapshot,
65
59
  IDocumentMessage,
66
- ISnapshotTree,
67
- ISummaryContent,
68
- MessageType,
69
60
  ISequencedDocumentMessage,
70
61
  ISignalMessage,
71
- type ISummaryContext,
62
+ ISnapshot,
63
+ ISnapshotTree,
64
+ ISummaryContent,
65
+ ISummaryContext,
72
66
  } from "@fluidframework/driver-definitions/internal";
67
+ import { FetchSource, MessageType } from "@fluidframework/driver-definitions/internal";
73
68
  import { readAndParse } from "@fluidframework/driver-utils/internal";
74
69
  import type { IIdCompressor } from "@fluidframework/id-compressor";
75
70
  import type {
@@ -78,13 +73,11 @@ import type {
78
73
  SerializedIdCompressorWithNoSession,
79
74
  SerializedIdCompressorWithOngoingSession,
80
75
  } from "@fluidframework/id-compressor/internal";
81
- import {
76
+ import type {
82
77
  ISummaryTreeWithStats,
83
78
  ITelemetryContext,
84
79
  IGarbageCollectionData,
85
80
  CreateChildSummarizerNodeParam,
86
- FlushMode,
87
- FlushModeExperimental,
88
81
  IDataStore,
89
82
  IEnvelope,
90
83
  IFluidDataStoreContextDetached,
@@ -93,11 +86,15 @@ import {
93
86
  InboundAttachMessage,
94
87
  NamedFluidDataStoreRegistryEntries,
95
88
  SummarizeInternalFn,
89
+ IInboundSignalMessage,
90
+ IRuntimeMessagesContent,
91
+ ISummarizerNodeWithGC,
92
+ } from "@fluidframework/runtime-definitions/internal";
93
+ import {
94
+ FlushMode,
95
+ FlushModeExperimental,
96
96
  channelsTreeName,
97
97
  gcTreeKey,
98
- IInboundSignalMessage,
99
- type IRuntimeMessagesContent,
100
- type ISummarizerNodeWithGC,
101
98
  } from "@fluidframework/runtime-definitions/internal";
102
99
  import {
103
100
  GCDataBuilder,
@@ -108,23 +105,21 @@ import {
108
105
  calculateStats,
109
106
  create404Response,
110
107
  exceptionToResponse,
111
- responseToException,
112
108
  seqFromTree,
113
109
  } from "@fluidframework/runtime-utils/internal";
114
110
  import type {
111
+ IEventSampler,
115
112
  IFluidErrorBase,
116
113
  ITelemetryGenericEventExt,
117
- TelemetryEventPropertyTypeExt,
114
+ ITelemetryLoggerExt,
115
+ MonitoringContext,
118
116
  } from "@fluidframework/telemetry-utils/internal";
119
117
  import {
120
- ITelemetryLoggerExt,
121
118
  DataCorruptionError,
122
119
  DataProcessingError,
123
120
  extractSafePropertiesFromMessage,
124
121
  GenericError,
125
- IEventSampler,
126
122
  LoggingError,
127
- MonitoringContext,
128
123
  PerformanceEvent,
129
124
  // eslint-disable-next-line import/no-deprecated
130
125
  TaggedLoggerAdapter,
@@ -147,7 +142,6 @@ import {
147
142
  blobsTreeName,
148
143
  isBlobPath,
149
144
  loadBlobManagerLoadInfo,
150
- // eslint-disable-next-line import/no-deprecated
151
145
  type IBlobManagerLoadInfo,
152
146
  } from "./blobManager/index.js";
153
147
  import {
@@ -155,7 +149,7 @@ import {
155
149
  getSummaryForDatastores,
156
150
  wrapContext,
157
151
  } from "./channelCollection.js";
158
- import { IPerfSignalReport, ReportOpPerfTelemetry } from "./connectionTelemetry.js";
152
+ import { ReportOpPerfTelemetry } from "./connectionTelemetry.js";
159
153
  import { ContainerFluidHandleContext } from "./containerHandleContext.js";
160
154
  import { channelToDataStore } from "./dataStore.js";
161
155
  import { FluidDataStoreRegistry } from "./dataStoreRegistry.js";
@@ -165,18 +159,15 @@ import {
165
159
  } from "./deltaManagerProxies.js";
166
160
  import { DeltaScheduler } from "./deltaScheduler.js";
167
161
  import {
168
- // eslint-disable-next-line import/no-deprecated
169
162
  GCNodeType,
170
163
  GarbageCollector,
171
164
  IGCRuntimeOptions,
172
- // eslint-disable-next-line import/no-deprecated
173
165
  IGCStats,
174
166
  IGarbageCollector,
175
167
  gcGenerationOptionName,
176
168
  type GarbageCollectionMessage,
177
169
  } from "./gc/index.js";
178
170
  import { InboundBatchAggregator } from "./inboundBatchAggregator.js";
179
- import { RuntimeCompatDetails, validateLoaderCompatibility } from "./layerCompatState.js";
180
171
  import {
181
172
  ContainerMessageType,
182
173
  type ContainerRuntimeDocumentSchemaMessage,
@@ -210,39 +201,32 @@ import {
210
201
  IPendingLocalState,
211
202
  PendingStateManager,
212
203
  } from "./pendingStateManager.js";
204
+ import { RunCounter } from "./runCounter.js";
205
+ import {
206
+ runtimeCompatDetailsForLoader,
207
+ validateLoaderCompatibility,
208
+ } from "./runtimeLayerCompatState.js";
209
+ import { SignalTelemetryManager } from "./signalTelemetryProcessing.js";
213
210
  import {
214
- // eslint-disable-next-line import/no-deprecated
215
211
  DocumentsSchemaController,
216
212
  EnqueueSummarizeResult,
217
213
  IBaseSummarizeResult,
218
- // eslint-disable-next-line import/no-deprecated
219
214
  IConnectableRuntime,
220
- // eslint-disable-next-line import/no-deprecated
221
215
  IContainerRuntimeMetadata,
222
- // eslint-disable-next-line import/no-deprecated
223
216
  ICreateContainerMetadata,
224
- // eslint-disable-next-line import/no-deprecated
225
217
  type IDocumentSchemaChangeMessage,
226
- // eslint-disable-next-line import/no-deprecated
227
218
  type IDocumentSchemaCurrent,
228
219
  IEnqueueSummarizeOptions,
229
220
  IGenerateSummaryTreeResult,
230
221
  IGeneratedSummaryStats,
231
222
  IOnDemandSummarizeOptions,
232
- // eslint-disable-next-line import/no-deprecated
233
223
  IRefreshSummaryAckOptions,
234
224
  IRootSummarizerNodeWithGC,
235
- // eslint-disable-next-line import/no-deprecated
236
225
  ISerializedElection,
237
- // eslint-disable-next-line import/no-deprecated
238
226
  ISubmitSummaryOptions,
239
227
  ISummarizeResults,
240
- ISummarizer,
241
- // eslint-disable-next-line import/no-deprecated
242
228
  ISummarizerInternalsProvider,
243
- // eslint-disable-next-line import/no-deprecated
244
229
  ISummarizerRuntime,
245
- // eslint-disable-next-line import/no-deprecated
246
230
  ISummaryMetadataMessage,
247
231
  IdCompressorMode,
248
232
  OrderedClientCollection,
@@ -250,7 +234,6 @@ import {
250
234
  RetriableSummaryError,
251
235
  RunWhileConnectedCoordinator,
252
236
  SubmitSummaryResult,
253
- // eslint-disable-next-line import/no-deprecated
254
237
  Summarizer,
255
238
  SummarizerClientElection,
256
239
  SummaryCollection,
@@ -266,8 +249,13 @@ import {
266
249
  rootHasIsolatedChannels,
267
250
  summarizerClientType,
268
251
  wrapSummaryInChannelsTree,
269
- // eslint-disable-next-line import/no-deprecated
270
252
  type IDocumentSchemaFeatures,
253
+ formCreateSummarizerFn,
254
+ summarizerRequestUrl,
255
+ validateSummaryHeuristicConfiguration,
256
+ ISummaryConfiguration,
257
+ DefaultSummaryConfiguration,
258
+ isSummariesDisabled,
271
259
  } from "./summary/index.js";
272
260
  import { Throttler, formExponentialFn } from "./throttler.js";
273
261
 
@@ -300,154 +288,6 @@ function getUnknownMessageTypeError(
300
288
  );
301
289
  }
302
290
 
303
- /**
304
- * @legacy
305
- * @alpha
306
- */
307
- export interface ISummaryBaseConfiguration {
308
- /**
309
- * Delay before first attempt to spawn summarizing container.
310
- */
311
- initialSummarizerDelayMs: number;
312
-
313
- /**
314
- * Defines the maximum allowed time to wait for a pending summary ack.
315
- * The maximum amount of time client will wait for a summarize is the minimum of
316
- * maxSummarizeAckWaitTime (currently 3 * 60 * 1000) and maxAckWaitTime.
317
- */
318
- maxAckWaitTime: number;
319
- /**
320
- * Defines the maximum number of Ops in between Summaries that can be
321
- * allowed before forcibly electing a new summarizer client.
322
- */
323
- maxOpsSinceLastSummary: number;
324
- }
325
-
326
- /**
327
- * @legacy
328
- * @alpha
329
- */
330
- export interface ISummaryConfigurationHeuristics extends ISummaryBaseConfiguration {
331
- state: "enabled";
332
- /**
333
- * Defines the maximum allowed time, since the last received Ack, before running the summary
334
- * with reason maxTime.
335
- * For example, say we receive ops one by one just before the idle time is triggered.
336
- * In this case, we still want to run a summary since it's been a while since the last summary.
337
- */
338
- maxTime: number;
339
- /**
340
- * Defines the maximum number of Ops, since the last received Ack, that can be allowed
341
- * before running the summary with reason maxOps.
342
- */
343
- maxOps: number;
344
- /**
345
- * Defines the minimum number of Ops, since the last received Ack, that can be allowed
346
- * before running the last summary.
347
- */
348
- minOpsForLastSummaryAttempt: number;
349
- /**
350
- * Defines the lower boundary for the allowed time in between summarizations.
351
- * Pairs with maxIdleTime to form a range.
352
- * For example, if we only receive 1 op, we don't want to have the same idle time as say 100 ops.
353
- * Based on the boundaries we set in minIdleTime and maxIdleTime, the idle time will change
354
- * linearly depending on the number of ops we receive.
355
- */
356
- minIdleTime: number;
357
- /**
358
- * Defines the upper boundary for the allowed time in between summarizations.
359
- * Pairs with minIdleTime to form a range.
360
- * For example, if we only receive 1 op, we don't want to have the same idle time as say 100 ops.
361
- * Based on the boundaries we set in minIdleTime and maxIdleTime, the idle time will change
362
- * linearly depending on the number of ops we receive.
363
- */
364
- maxIdleTime: number;
365
- /**
366
- * Runtime op weight to use in heuristic summarizing.
367
- * This number is a multiplier on the number of runtime ops we process when running summarize heuristics.
368
- * For example: (multiplier) * (number of runtime ops) = weighted number of runtime ops
369
- */
370
- runtimeOpWeight: number;
371
- /**
372
- * Non-runtime op weight to use in heuristic summarizing
373
- * This number is a multiplier on the number of non-runtime ops we process when running summarize heuristics.
374
- * For example: (multiplier) * (number of non-runtime ops) = weighted number of non-runtime ops
375
- */
376
- nonRuntimeOpWeight: number;
377
-
378
- /**
379
- * Number of ops since last summary needed before a non-runtime op can trigger running summary heuristics.
380
- *
381
- * Note: Any runtime ops sent before the threshold is reached will trigger heuristics normally.
382
- * This threshold ONLY applies to non-runtime ops triggering summaries.
383
- *
384
- * For example: Say the threshold is 20. Sending 19 non-runtime ops will not trigger any heuristic checks.
385
- * Sending the 20th non-runtime op will trigger the heuristic checks for summarizing.
386
- */
387
- nonRuntimeHeuristicThreshold?: number;
388
- }
389
-
390
- /**
391
- * @legacy
392
- * @alpha
393
- */
394
- export interface ISummaryConfigurationDisableSummarizer {
395
- state: "disabled";
396
- }
397
-
398
- /**
399
- * @legacy
400
- * @alpha
401
- */
402
- export interface ISummaryConfigurationDisableHeuristics extends ISummaryBaseConfiguration {
403
- state: "disableHeuristics";
404
- }
405
-
406
- /**
407
- * @legacy
408
- * @alpha
409
- */
410
- export type ISummaryConfiguration =
411
- | ISummaryConfigurationDisableSummarizer
412
- | ISummaryConfigurationDisableHeuristics
413
- | ISummaryConfigurationHeuristics;
414
-
415
- export function isSummariesDisabled(
416
- config: ISummaryConfiguration,
417
- ): config is ISummaryConfigurationDisableSummarizer {
418
- return config.state === "disabled";
419
- }
420
-
421
- /**
422
- * @legacy
423
- * @alpha
424
- */
425
- export const DefaultSummaryConfiguration: ISummaryConfiguration = {
426
- state: "enabled",
427
-
428
- minIdleTime: 0,
429
-
430
- maxIdleTime: 30 * 1000, // 30 secs.
431
-
432
- maxTime: 60 * 1000, // 1 min.
433
-
434
- maxOps: 100, // Summarize if 100 weighted ops received since last snapshot.
435
-
436
- minOpsForLastSummaryAttempt: 10,
437
-
438
- maxAckWaitTime: 3 * 60 * 1000, // 3 mins.
439
-
440
- maxOpsSinceLastSummary: 7000,
441
-
442
- initialSummarizerDelayMs: 5 * 1000, // 5 secs.
443
-
444
- nonRuntimeOpWeight: 0.1,
445
-
446
- runtimeOpWeight: 1,
447
-
448
- nonRuntimeHeuristicThreshold: 20,
449
- };
450
-
451
291
  /**
452
292
  * @legacy
453
293
  * @alpha
@@ -565,7 +405,7 @@ export interface IContainerRuntimeOptions {
565
405
  *
566
406
  * These options are not available to consumers when creating a new container runtime,
567
407
  * but we do need to expose them for internal use, e.g. when configuring the container runtime
568
- * to ensure compability with older versions.
408
+ * to ensure compatibility with older versions.
569
409
  *
570
410
  * @internal
571
411
  */
@@ -587,9 +427,7 @@ export interface IContainerRuntimeOptionsInternal extends IContainerRuntimeOptio
587
427
 
588
428
  /**
589
429
  * Error responses when requesting a deleted object will have this header set to true
590
- * @legacy
591
- * @alpha
592
- * @deprecated This type will be moved to internal in 2.30. External usage is not necessary or supported.
430
+ * @internal
593
431
  */
594
432
  export const DeletedResponseHeaderKey = "wasDeleted";
595
433
  /**
@@ -782,50 +620,6 @@ export const makeLegacySendBatchFn =
782
620
  return clientSequenceNumber;
783
621
  };
784
622
 
785
- const summarizerRequestUrl = "_summarizer";
786
-
787
- /**
788
- * Create and retrieve the summmarizer
789
- */
790
- async function createSummarizer(loader: ILoader, url: string): Promise<ISummarizer> {
791
- const request: IRequest = {
792
- headers: {
793
- [LoaderHeader.cache]: false,
794
- [LoaderHeader.clientDetails]: {
795
- capabilities: { interactive: false },
796
- type: summarizerClientType,
797
- },
798
- [DriverHeader.summarizingClient]: true,
799
- [LoaderHeader.reconnect]: false,
800
- },
801
- url,
802
- };
803
-
804
- const resolvedContainer = await loader.resolve(request);
805
- let fluidObject: FluidObject<ISummarizer> | undefined;
806
-
807
- // Older containers may not have the "getEntryPoint" API
808
- // ! This check will need to stay until LTS of loader moves past 2.0.0-internal.7.0.0
809
- if (resolvedContainer.getEntryPoint === undefined) {
810
- // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-explicit-any
811
- const response = (await (resolvedContainer as any).request({
812
- url: `/${summarizerRequestUrl}`,
813
- })) as IResponse;
814
- if (response.status !== 200 || response.mimeType !== "fluid/object") {
815
- throw responseToException(response, request);
816
- }
817
- // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
818
- fluidObject = response.value;
819
- } else {
820
- fluidObject = await resolvedContainer.getEntryPoint();
821
- }
822
-
823
- if (fluidObject?.ISummarizer === undefined) {
824
- throw new UsageError("Fluid object does not implement ISummarizer");
825
- }
826
- return fluidObject.ISummarizer;
827
- }
828
-
829
623
  /**
830
624
  * Extract last message from the snapshot metadata.
831
625
  * Uses legacy property if not using explicit schema control, otherwise uses the new property.
@@ -833,9 +627,7 @@ async function createSummarizer(loader: ILoader, url: string): Promise<ISummariz
833
627
  * Please see addMetadataToSummary() as well
834
628
  */
835
629
  function lastMessageFromMetadata(
836
- // eslint-disable-next-line import/no-deprecated
837
630
  metadata: IContainerRuntimeMetadata | undefined,
838
- // eslint-disable-next-line import/no-deprecated
839
631
  ): ISummaryMetadataMessage | undefined {
840
632
  return metadata?.documentSchema?.runtime?.explicitSchemaControl
841
633
  ? metadata?.lastMessage
@@ -913,8 +705,6 @@ export async function loadContainerRuntime(
913
705
 
914
706
  const defaultMaxConsecutiveReconnects = 7;
915
707
 
916
- const defaultTelemetrySignalSampleCount = 100;
917
-
918
708
  /**
919
709
  * Represents the runtime of the container. Contains helper functions/state of the container.
920
710
  * It will define the store level mappings.
@@ -926,9 +716,7 @@ export class ContainerRuntime
926
716
  implements
927
717
  IContainerRuntime,
928
718
  IRuntime,
929
- // eslint-disable-next-line import/no-deprecated
930
719
  ISummarizerRuntime,
931
- // eslint-disable-next-line import/no-deprecated
932
720
  ISummarizerInternalsProvider,
933
721
  IProvideFluidHandleContext,
934
722
  IProvideLayerCompatDetails
@@ -952,7 +740,7 @@ export class ContainerRuntime
952
740
  context: IContainerContext;
953
741
  registryEntries: NamedFluidDataStoreRegistryEntries;
954
742
  existing: boolean;
955
- runtimeOptions?: IContainerRuntimeOptions; // May also include options from IContainerRuntimeOptionsInternal
743
+ runtimeOptions?: IContainerRuntimeOptionsInternal;
956
744
  containerScope?: FluidObject;
957
745
  containerRuntimeCtor?: typeof ContainerRuntime;
958
746
  /**
@@ -967,7 +755,7 @@ export class ContainerRuntime
967
755
  existing,
968
756
  requestHandler,
969
757
  provideEntryPoint,
970
- runtimeOptions = {} satisfies IContainerRuntimeOptions,
758
+ runtimeOptions = {} satisfies IContainerRuntimeOptionsInternal,
971
759
  containerScope = {},
972
760
  containerRuntimeCtor = ContainerRuntime,
973
761
  } = params;
@@ -1032,16 +820,16 @@ export class ContainerRuntime
1032
820
  tryFetchBlob<ReturnType<DuplicateBatchDetector["getRecentBatchInfoForSummary"]>>(
1033
821
  recentBatchInfoBlobName,
1034
822
  ),
1035
- // eslint-disable-next-line import/no-deprecated
823
+
1036
824
  tryFetchBlob<IContainerRuntimeMetadata>(metadataBlobName),
1037
- // eslint-disable-next-line import/no-deprecated
825
+
1038
826
  tryFetchBlob<ISerializedElection>(electedSummarizerBlobName),
1039
827
  tryFetchBlob<[string, string][]>(aliasBlobName),
1040
828
  tryFetchBlob<SerializedIdCompressorWithNoSession>(idCompressorBlobName),
1041
829
  ]);
1042
830
 
1043
831
  // read snapshot blobs needed for BlobManager to load
1044
- const blobManagerSnapshot = await loadBlobManagerLoadInfo(context);
832
+ const blobManagerLoadInfo = await loadBlobManagerLoadInfo(context);
1045
833
 
1046
834
  const messageAtLastSummary = lastMessageFromMetadata(metadata);
1047
835
 
@@ -1170,7 +958,6 @@ export class ContainerRuntime
1170
958
  compressionOptions.minimumBatchSizeInBytes !== Number.POSITIVE_INFINITY &&
1171
959
  compressionOptions.compressionAlgorithm === "lz4";
1172
960
 
1173
- // eslint-disable-next-line import/no-deprecated
1174
961
  const documentSchemaController = new DocumentsSchemaController(
1175
962
  existing,
1176
963
  protocolSequenceNumber,
@@ -1219,7 +1006,7 @@ export class ContainerRuntime
1219
1006
  containerScope,
1220
1007
  logger,
1221
1008
  existing,
1222
- blobManagerSnapshot,
1009
+ blobManagerLoadInfo,
1223
1010
  context.storage,
1224
1011
  createIdCompressorFn,
1225
1012
  documentSchemaController,
@@ -1308,11 +1095,9 @@ export class ContainerRuntime
1308
1095
  * this op roundtrips, compression will be On. Client can't send compressed ops until it's change in schema.
1309
1096
  */
1310
1097
  public get sessionSchema(): {
1311
- // eslint-disable-next-line import/no-deprecated
1312
1098
  [P in keyof IDocumentSchemaFeatures]?: IDocumentSchemaFeatures[P] extends boolean
1313
1099
  ? true
1314
- : // eslint-disable-next-line import/no-deprecated
1315
- IDocumentSchemaFeatures[P];
1100
+ : IDocumentSchemaFeatures[P];
1316
1101
  } {
1317
1102
  return this.documentsSchemaController.sessionSchema.runtime;
1318
1103
  }
@@ -1394,7 +1179,7 @@ export class ContainerRuntime
1394
1179
 
1395
1180
  private readonly maxConsecutiveReconnects: number;
1396
1181
 
1397
- private _orderSequentiallyCalls: number = 0;
1182
+ private readonly batchRunner = new RunCounter();
1398
1183
  private readonly _flushMode: FlushMode;
1399
1184
  private readonly offlineEnabled: boolean;
1400
1185
  private flushTaskExists = false;
@@ -1409,23 +1194,16 @@ export class ContainerRuntime
1409
1194
  */
1410
1195
  private delayConnectClientId?: string;
1411
1196
 
1412
- private ensureNoDataModelChangesCalls = 0;
1197
+ private readonly dataModelChangeRunner = new RunCounter();
1413
1198
 
1414
1199
  /**
1415
1200
  * Invokes the given callback and expects that no ops are submitted
1416
1201
  * until execution finishes. If an op is submitted, an error will be raised.
1417
1202
  *
1418
- * Can be disabled by feature gate `Fluid.ContainerRuntime.DisableOpReentryCheck`
1419
- *
1420
1203
  * @param callback - the callback to be invoked
1421
1204
  */
1422
1205
  public ensureNoDataModelChanges<T>(callback: () => T): T {
1423
- this.ensureNoDataModelChangesCalls++;
1424
- try {
1425
- return callback();
1426
- } finally {
1427
- this.ensureNoDataModelChangesCalls--;
1428
- }
1206
+ return this.dataModelChangeRunner.run(callback);
1429
1207
  }
1430
1208
 
1431
1209
  public get connected(): boolean {
@@ -1448,24 +1226,15 @@ export class ContainerRuntime
1448
1226
  private emitDirtyDocumentEvent = true;
1449
1227
  private readonly useDeltaManagerOpsProxy: boolean;
1450
1228
  private readonly closeSummarizerDelayMs: number;
1451
- private readonly _signalTracking: IPerfSignalReport = {
1452
- totalSignalsSentInLatencyWindow: 0,
1453
- signalsLost: 0,
1454
- signalsOutOfOrder: 0,
1455
- signalsSentSinceLastLatencyMeasurement: 0,
1456
- broadcastSignalSequenceNumber: 0,
1457
- signalTimestamp: 0,
1458
- roundTripSignalSequenceNumber: undefined,
1459
- trackingSignalSequenceNumber: undefined,
1460
- minimumTrackingSignalSequenceNumber: undefined,
1461
- };
1229
+
1230
+ private readonly signalTelemetryManager = new SignalTelemetryManager();
1462
1231
 
1463
1232
  /**
1464
1233
  * Summarizer is responsible for coordinating when to send generate and send summaries.
1465
1234
  * It is the main entry point for summary work.
1466
1235
  * It is created only by summarizing container (i.e. one with clientType === "summarizer")
1467
1236
  */
1468
- // eslint-disable-next-line import/no-deprecated
1237
+
1469
1238
  private readonly _summarizer?: Summarizer;
1470
1239
  private readonly deltaScheduler: DeltaScheduler;
1471
1240
  private readonly inboundBatchAggregator: InboundBatchAggregator;
@@ -1481,12 +1250,11 @@ export class ContainerRuntime
1481
1250
  /**
1482
1251
  * The last message processed at the time of the last summary.
1483
1252
  */
1484
- // eslint-disable-next-line import/no-deprecated
1253
+
1485
1254
  private messageAtLastSummary: ISummaryMetadataMessage | undefined;
1486
1255
 
1487
1256
  private readonly summariesDisabled: boolean;
1488
1257
 
1489
- // eslint-disable-next-line import/no-deprecated
1490
1258
  private readonly createContainerMetadata: ICreateContainerMetadata;
1491
1259
  /**
1492
1260
  * The summary number of the next summary that will be generated for this container. This is incremented every time
@@ -1538,30 +1306,41 @@ export class ContainerRuntime
1538
1306
  expiry: { policy: "absolute", durationMs: 60000 },
1539
1307
  });
1540
1308
 
1309
+ /**
1310
+ * The compatibility details of the Runtime layer that is exposed to the Loader layer
1311
+ * for validating Loader-Runtime compatibility.
1312
+ */
1541
1313
  public get ILayerCompatDetails(): ILayerCompatDetails {
1542
- return RuntimeCompatDetails;
1314
+ return runtimeCompatDetailsForLoader;
1543
1315
  }
1544
1316
 
1317
+ /**
1318
+ * If true, will skip Outbox flushing before processing an incoming message,
1319
+ * and instead the Outbox will check for a split batch on every submit.
1320
+ * This is a kill-bit switch for this simplification of logic, in case it causes unexpected issues.
1321
+ */
1322
+ private readonly disableFlushBeforeProcess: boolean;
1323
+
1545
1324
  /***/
1546
1325
  protected constructor(
1547
1326
  context: IContainerContext,
1548
1327
  private readonly registry: IFluidDataStoreRegistry,
1549
- // eslint-disable-next-line import/no-deprecated
1328
+
1550
1329
  private readonly metadata: IContainerRuntimeMetadata | undefined,
1551
- // eslint-disable-next-line import/no-deprecated
1330
+
1552
1331
  electedSummarizerData: ISerializedElection | undefined,
1553
1332
  chunks: [string, string[]][],
1554
1333
  dataStoreAliasMap: [string, string][],
1555
- baseRuntimeOptions: Readonly<Required<IContainerRuntimeOptions>>,
1334
+ runtimeOptions: Readonly<Required<IContainerRuntimeOptionsInternal>>,
1556
1335
  private readonly containerScope: FluidObject,
1557
1336
  // Create a custom ITelemetryBaseLogger to output telemetry events.
1558
1337
  public readonly baseLogger: ITelemetryBaseLogger,
1559
1338
  existing: boolean,
1560
- // eslint-disable-next-line import/no-deprecated
1561
- blobManagerSnapshot: IBlobManagerLoadInfo,
1339
+
1340
+ blobManagerLoadInfo: IBlobManagerLoadInfo,
1562
1341
  private readonly _storage: IDocumentStorageService,
1563
1342
  private readonly createIdCompressor: () => Promise<IIdCompressor & IIdCompressorCore>,
1564
- // eslint-disable-next-line import/no-deprecated
1343
+
1565
1344
  private readonly documentsSchemaController: DocumentsSchemaController,
1566
1345
  featureGatesForTelemetry: Record<string, boolean | number | undefined>,
1567
1346
  provideEntryPoint: (containerRuntime: IContainerRuntime) => Promise<FluidObject>,
@@ -1574,7 +1353,7 @@ export class ContainerRuntime
1574
1353
  // the defaults
1575
1354
  ...DefaultSummaryConfiguration,
1576
1355
  // the runtime configuration overrides
1577
- ...baseRuntimeOptions.summaryOptions?.summaryConfigOverrides,
1356
+ ...runtimeOptions.summaryOptions?.summaryConfigOverrides,
1578
1357
  },
1579
1358
  recentBatchInfo?: [number, string][],
1580
1359
  ) {
@@ -1603,14 +1382,13 @@ export class ContainerRuntime
1603
1382
  // In old loaders without dispose functionality, closeFn is equivalent but will also switch container to readonly mode
1604
1383
  this.disposeFn = disposeFn ?? closeFn;
1605
1384
 
1606
- const maybeLoaderCompatDetails = context as FluidObject<ILayerCompatDetails>;
1607
- validateLoaderCompatibility(maybeLoaderCompatDetails.ILayerCompatDetails, this.disposeFn);
1385
+ // Validate that the Loader is compatible with this Runtime.
1386
+ const maybeloaderCompatDetailsForRuntime = context as FluidObject<ILayerCompatDetails>;
1387
+ validateLoaderCompatibility(
1388
+ maybeloaderCompatDetailsForRuntime.ILayerCompatDetails,
1389
+ this.disposeFn,
1390
+ );
1608
1391
 
1609
- // Backfill in defaults for the internal runtimeOptions, since they may not be present on the provided runtimeOptions object
1610
- const runtimeOptions = {
1611
- flushMode: defaultFlushMode,
1612
- ...baseRuntimeOptions,
1613
- };
1614
1392
  this.mc = createChildMonitoringContext({
1615
1393
  logger: this.baseLogger,
1616
1394
  namespace: "ContainerRuntime",
@@ -1663,6 +1441,25 @@ export class ContainerRuntime
1663
1441
  this.on("dirty", () => context.updateDirtyContainerState(true));
1664
1442
  this.on("saved", () => context.updateDirtyContainerState(false));
1665
1443
 
1444
+ // Telemetry for when the container is attached and subsequently saved for the first time.
1445
+ // These events are useful for investigating the validity of container "saved" eventing upon attach.
1446
+ // See this.setAttachState() and this.updateDocumentDirtyState() for more details on "attached" and "saved" events.
1447
+ this.once("attached", () => {
1448
+ this.mc.logger.sendTelemetryEvent({
1449
+ eventName: "Attached",
1450
+ details: {
1451
+ dirtyContainer: this.dirtyContainer,
1452
+ hasPendingMessages: this.hasPendingMessages(),
1453
+ },
1454
+ });
1455
+ });
1456
+ this.once("saved", () =>
1457
+ this.mc.logger.sendTelemetryEvent({
1458
+ eventName: "Saved",
1459
+ details: { attachState: this.attachState },
1460
+ }),
1461
+ );
1462
+
1666
1463
  // In cases of summarizer, we want to dispose instead since consumer doesn't interact with this container
1667
1464
  this.closeFn = isSummarizerClient ? this.disposeFn : closeFn;
1668
1465
 
@@ -1762,7 +1559,7 @@ export class ContainerRuntime
1762
1559
  this.handleContext = new ContainerFluidHandleContext("", this);
1763
1560
 
1764
1561
  if (summaryConfiguration.state === "enabled") {
1765
- this.validateSummaryHeuristicConfiguration(summaryConfiguration);
1562
+ validateSummaryHeuristicConfiguration(summaryConfiguration);
1766
1563
  }
1767
1564
 
1768
1565
  this.summariesDisabled = isSummariesDisabled(summaryConfiguration);
@@ -1785,7 +1582,7 @@ export class ContainerRuntime
1785
1582
  // If the context has ILayerCompatDetails, it supports referenceSequenceNumbers since that features
1786
1583
  // predates ILayerCompatDetails.
1787
1584
  const referenceSequenceNumbersSupported =
1788
- maybeLoaderCompatDetails.ILayerCompatDetails === undefined
1585
+ maybeloaderCompatDetailsForRuntime.ILayerCompatDetails === undefined
1789
1586
  ? supportedFeatures?.get("referenceSequenceNumbers") === true
1790
1587
  : true;
1791
1588
  if (
@@ -1883,13 +1680,14 @@ export class ContainerRuntime
1883
1680
  // what is the interface of passing signals, we need the
1884
1681
  // downstream stores to wrap the signal.
1885
1682
  parentContext.submitSignal = (type: string, content: unknown, targetClientId?: string) => {
1683
+ // Future: Can the `content` argument type be IEnvelope?
1684
+ // verifyNotClosed is called in FluidDataStoreContext, which is *the* expected caller.
1886
1685
  const envelope1 = content as IEnvelope;
1887
- const envelope2 = this.createNewSignalEnvelope(
1888
- envelope1.address,
1889
- type,
1890
- envelope1.contents,
1891
- );
1892
- return this.submitEnvelopedSignal(envelope2, targetClientId);
1686
+ const envelope2 = createNewSignalEnvelope(envelope1.address, type, envelope1.contents);
1687
+ if (targetClientId === undefined) {
1688
+ this.signalTelemetryManager.applyTrackingToBroadcastSignalEnvelope(envelope2);
1689
+ }
1690
+ this.submitSignalFn(envelope2, targetClientId);
1893
1691
  };
1894
1692
 
1895
1693
  let snapshot: ISnapshot | ISnapshotTree | undefined = getSummaryForDatastores(
@@ -1919,8 +1717,8 @@ export class ContainerRuntime
1919
1717
 
1920
1718
  this.blobManager = new BlobManager({
1921
1719
  routeContext: this.handleContext,
1922
- snapshot: blobManagerSnapshot,
1923
- getStorage: () => this.storage,
1720
+ blobManagerLoadInfo,
1721
+ storage: this.storage,
1924
1722
  sendBlobAttachOp: (localId: string, blobId?: string) => {
1925
1723
  if (!this.disposed) {
1926
1724
  this.submit(
@@ -1956,12 +1754,11 @@ export class ContainerRuntime
1956
1754
  createChildLogger({ logger: this.baseLogger, namespace: "InboundBatchAggregator" }),
1957
1755
  );
1958
1756
 
1959
- const disablePartialFlush = this.mc.config.getBoolean(
1960
- "Fluid.ContainerRuntime.DisablePartialFlush",
1961
- );
1962
-
1963
1757
  const legacySendBatchFn = makeLegacySendBatchFn(submitFn, this.innerDeltaManager);
1964
1758
 
1759
+ this.disableFlushBeforeProcess =
1760
+ this.mc.config.getBoolean("Fluid.ContainerRuntime.DisableFlushBeforeProcess") === true;
1761
+
1965
1762
  this.outbox = new Outbox({
1966
1763
  shouldSend: () => this.canSendOps(),
1967
1764
  pendingStateManager: this.pendingStateManager,
@@ -1972,16 +1769,18 @@ export class ContainerRuntime
1972
1769
  config: {
1973
1770
  compressionOptions,
1974
1771
  maxBatchSizeInBytes: runtimeOptions.maxBatchSizeInBytes,
1975
- disablePartialFlush: disablePartialFlush === true,
1772
+ // If we disable flush before process, we must be ready to flush partial batches
1773
+ flushPartialBatches: this.disableFlushBeforeProcess,
1976
1774
  },
1977
1775
  logger: this.mc.logger,
1978
1776
  groupingManager: opGroupingManager,
1979
1777
  getCurrentSequenceNumbers: () => ({
1778
+ // Note: These sequence numbers only change when DeltaManager processes an incoming op
1980
1779
  referenceSequenceNumber: this.deltaManager.lastSequenceNumber,
1981
1780
  clientSequenceNumber: this._processedClientSequenceNumber,
1982
1781
  }),
1983
1782
  reSubmit: this.reSubmit.bind(this),
1984
- opReentrancy: () => this.ensureNoDataModelChangesCalls > 0,
1783
+ opReentrancy: () => this.dataModelChangeRunner.running,
1985
1784
  closeContainer: this.closeFn,
1986
1785
  });
1987
1786
 
@@ -2058,14 +1857,13 @@ export class ContainerRuntime
2058
1857
  );
2059
1858
 
2060
1859
  if (isSummarizerClient) {
2061
- // eslint-disable-next-line import/no-deprecated
2062
1860
  this._summarizer = new Summarizer(
2063
1861
  this /* ISummarizerRuntime */,
2064
1862
  () => summaryConfiguration,
2065
1863
  this /* ISummarizerInternalsProvider */,
2066
1864
  this.handleContext,
2067
1865
  summaryCollection,
2068
- // eslint-disable-next-line import/no-deprecated
1866
+
2069
1867
  async (runtime: IConnectableRuntime) =>
2070
1868
  RunWhileConnectedCoordinator.create(
2071
1869
  runtime,
@@ -2103,7 +1901,7 @@ export class ContainerRuntime
2103
1901
  this, // IConnectedState
2104
1902
  summaryCollection,
2105
1903
  this.baseLogger,
2106
- this.formCreateSummarizerFn(loader),
1904
+ formCreateSummarizerFn(loader),
2107
1905
  new Throttler(
2108
1906
  60 * 1000, // 60 sec delay window
2109
1907
  30 * 1000, // 30 sec max delay
@@ -2146,14 +1944,14 @@ export class ContainerRuntime
2146
1944
  summaryFormatVersion: metadata?.summaryFormatVersion,
2147
1945
  disableIsolatedChannels: metadata?.disableIsolatedChannels,
2148
1946
  gcVersion: metadata?.gcFeature,
2149
- options: JSON.stringify(baseRuntimeOptions),
1947
+ options: JSON.stringify(runtimeOptions),
2150
1948
  idCompressorModeMetadata: metadata?.documentSchema?.runtime?.idCompressorMode,
2151
1949
  idCompressorMode: this.sessionSchema.idCompressorMode,
2152
1950
  sessionRuntimeSchema: JSON.stringify(this.sessionSchema),
2153
1951
  featureGates: JSON.stringify({
2154
1952
  ...featureGatesForTelemetry,
2155
- disablePartialFlush,
2156
1953
  closeSummarizerDelayOverride,
1954
+ disableFlushBeforeProcess: this.disableFlushBeforeProcess,
2157
1955
  }),
2158
1956
  telemetryDocumentId: this.telemetryDocumentId,
2159
1957
  groupedBatchingEnabled: this.groupedBatchingEnabled,
@@ -2175,7 +1973,6 @@ export class ContainerRuntime
2175
1973
  this.skipSavedCompressorOps = pendingRuntimeState?.pendingIdCompressorState !== undefined;
2176
1974
  }
2177
1975
 
2178
- // eslint-disable-next-line import/no-deprecated
2179
1976
  public onSchemaChange(schema: IDocumentSchemaCurrent): void {
2180
1977
  this.mc.logger.sendTelemetryEvent({
2181
1978
  eventName: "SchemaChangeAccept",
@@ -2453,13 +2250,11 @@ export class ContainerRuntime
2453
2250
 
2454
2251
  if (id === blobManagerBasePath && requestParser.isLeaf(2)) {
2455
2252
  const blob = await this.blobManager.getBlob(requestParser.pathParts[1]);
2456
- return blob
2457
- ? {
2458
- status: 200,
2459
- mimeType: "fluid/object",
2460
- value: blob,
2461
- }
2462
- : create404Response(request);
2253
+ return {
2254
+ status: 200,
2255
+ mimeType: "fluid/object",
2256
+ value: blob,
2257
+ };
2463
2258
  } else if (requestParser.pathParts.length > 0) {
2464
2259
  return await this.channelCollection.request(request);
2465
2260
  }
@@ -2499,7 +2294,6 @@ export class ContainerRuntime
2499
2294
  // Is document schema explicit control on?
2500
2295
  const explicitSchemaControl = documentSchema?.runtime.explicitSchemaControl;
2501
2296
 
2502
- // eslint-disable-next-line import/no-deprecated
2503
2297
  const metadata: IContainerRuntimeMetadata = {
2504
2298
  ...this.createContainerMetadata,
2505
2299
  // Increment the summary number for the next summary that will be generated.
@@ -2513,8 +2307,7 @@ export class ContainerRuntime
2513
2307
  // last message's sequence number.
2514
2308
  // See also lastMessageFromMetadata()
2515
2309
  message: explicitSchemaControl
2516
- ? // eslint-disable-next-line import/no-deprecated
2517
- ({ sequenceNumber: -1 } as unknown as ISummaryMetadataMessage)
2310
+ ? ({ sequenceNumber: -1 } as unknown as ISummaryMetadataMessage)
2518
2311
  : message,
2519
2312
  lastMessage: explicitSchemaControl ? message : undefined,
2520
2313
  documentSchema,
@@ -2796,14 +2589,7 @@ export class ContainerRuntime
2796
2589
  0x3cd /* Connection is possible only if container exists in storage */,
2797
2590
  );
2798
2591
  if (changeOfState) {
2799
- this._signalTracking.signalsLost = 0;
2800
- this._signalTracking.signalsOutOfOrder = 0;
2801
- this._signalTracking.signalTimestamp = 0;
2802
- this._signalTracking.signalsSentSinceLastLatencyMeasurement = 0;
2803
- this._signalTracking.totalSignalsSentInLatencyWindow = 0;
2804
- this._signalTracking.roundTripSignalSequenceNumber = undefined;
2805
- this._signalTracking.trackingSignalSequenceNumber = undefined;
2806
- this._signalTracking.minimumTrackingSignalSequenceNumber = undefined;
2592
+ this.signalTelemetryManager.resetTracking();
2807
2593
  }
2808
2594
  }
2809
2595
 
@@ -2853,6 +2639,26 @@ export class ContainerRuntime
2853
2639
 
2854
2640
  this.verifyNotClosed();
2855
2641
 
2642
+ if (!this.disableFlushBeforeProcess) {
2643
+ // Reference Sequence Number may be about to change, and it must be consistent across a batch, so flush now
2644
+ this.outbox.flush();
2645
+ }
2646
+
2647
+ this.ensureNoDataModelChanges(() => {
2648
+ this.processInboundMessageOrBatch(messageCopy, local);
2649
+ });
2650
+ }
2651
+
2652
+ /**
2653
+ * Implementation of core logic for {@link ContainerRuntime.process}, once preconditions are established
2654
+ *
2655
+ * @param messageCopy - Shallow copy of the sequenced message. If it's a virtualized batch, we'll process
2656
+ * all messages in the batch here.
2657
+ */
2658
+ private processInboundMessageOrBatch(
2659
+ messageCopy: ISequencedDocumentMessage,
2660
+ local: boolean,
2661
+ ): void {
2856
2662
  // Whether or not the message appears to be a runtime message from an up-to-date client.
2857
2663
  // It may be a legacy runtime message (ie already unpacked and ContainerMessageType)
2858
2664
  // or something different, like a system message.
@@ -3014,9 +2820,7 @@ export class ContainerRuntime
3014
2820
  try {
3015
2821
  if (!runtimeBatch) {
3016
2822
  for (const { message } of messagesWithMetadata) {
3017
- this.ensureNoDataModelChanges(() => {
3018
- this.observeNonRuntimeMessage(message);
3019
- });
2823
+ this.observeNonRuntimeMessage(message);
3020
2824
  }
3021
2825
  return;
3022
2826
  }
@@ -3040,21 +2844,19 @@ export class ContainerRuntime
3040
2844
  if (!groupedBatch) {
3041
2845
  for (const { message, localOpMetadata } of messagesWithMetadata) {
3042
2846
  updateSequenceNumbers(message);
3043
- this.ensureNoDataModelChanges(() => {
3044
- this.validateAndProcessRuntimeMessages(
3045
- message as InboundSequencedContainerRuntimeMessage,
3046
- [
3047
- {
3048
- contents: message.contents,
3049
- localOpMetadata,
3050
- clientSequenceNumber: message.clientSequenceNumber,
3051
- },
3052
- ],
3053
- local,
3054
- savedOp,
3055
- );
3056
- this.emit("op", message, true /* runtimeMessage */);
3057
- });
2847
+ this.validateAndProcessRuntimeMessages(
2848
+ message as InboundSequencedContainerRuntimeMessage,
2849
+ [
2850
+ {
2851
+ contents: message.contents,
2852
+ localOpMetadata,
2853
+ clientSequenceNumber: message.clientSequenceNumber,
2854
+ },
2855
+ ],
2856
+ local,
2857
+ savedOp,
2858
+ );
2859
+ this.emit("op", message, true /* runtimeMessage */);
3058
2860
  }
3059
2861
  return;
3060
2862
  }
@@ -3063,17 +2865,14 @@ export class ContainerRuntime
3063
2865
  let previousMessage: InboundSequencedContainerRuntimeMessage | undefined;
3064
2866
 
3065
2867
  // Process the previous bunch of messages.
3066
- const sendBunchedMessages = (): void => {
2868
+ const processBunchedMessages = (): void => {
3067
2869
  assert(previousMessage !== undefined, 0xa67 /* previous message must exist */);
3068
- this.ensureNoDataModelChanges(() => {
3069
- this.validateAndProcessRuntimeMessages(
3070
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
3071
- previousMessage!,
3072
- bunchedMessagesContent,
3073
- local,
3074
- savedOp,
3075
- );
3076
- });
2870
+ this.validateAndProcessRuntimeMessages(
2871
+ previousMessage,
2872
+ bunchedMessagesContent,
2873
+ local,
2874
+ savedOp,
2875
+ );
3077
2876
  bunchedMessagesContent = [];
3078
2877
  };
3079
2878
 
@@ -3085,7 +2884,7 @@ export class ContainerRuntime
3085
2884
  for (const { message, localOpMetadata } of messagesWithMetadata) {
3086
2885
  const currentMessage = updateSequenceNumbers(message);
3087
2886
  if (previousMessage && previousMessage.type !== currentMessage.type) {
3088
- sendBunchedMessages();
2887
+ processBunchedMessages();
3089
2888
  }
3090
2889
  previousMessage = currentMessage;
3091
2890
  bunchedMessagesContent.push({
@@ -3096,7 +2895,7 @@ export class ContainerRuntime
3096
2895
  }
3097
2896
 
3098
2897
  // Process the last bunch of messages.
3099
- sendBunchedMessages();
2898
+ processBunchedMessages();
3100
2899
 
3101
2900
  // Send the "op" events for the messages now that the ops have been processed.
3102
2901
  for (const { message } of messagesWithMetadata) {
@@ -3207,7 +3006,6 @@ export class ContainerRuntime
3207
3006
  }
3208
3007
  case ContainerMessageType.DocumentSchemaChange: {
3209
3008
  this.documentsSchemaController.processDocumentSchemaMessages(
3210
- // eslint-disable-next-line import/no-deprecated
3211
3009
  contents as IDocumentSchemaChangeMessage[],
3212
3010
  local,
3213
3011
  message.sequenceNumber,
@@ -3255,107 +3053,6 @@ export class ContainerRuntime
3255
3053
  }
3256
3054
  }
3257
3055
 
3258
- /**
3259
- * Emits the Signal event and update the perf signal data.
3260
- */
3261
- private sendSignalTelemetryEvent(): void {
3262
- const duration = Date.now() - this._signalTracking.signalTimestamp;
3263
- this.mc.logger.sendPerformanceEvent({
3264
- eventName: "SignalLatency",
3265
- details: {
3266
- duration, // Roundtrip duration of the tracked signal in milliseconds.
3267
- sent: this._signalTracking.totalSignalsSentInLatencyWindow, // Signals sent since the last logged SignalLatency event.
3268
- lost: this._signalTracking.signalsLost, // Signals lost since the last logged SignalLatency event.
3269
- outOfOrder: this._signalTracking.signalsOutOfOrder, // Out of order signals since the last logged SignalLatency event.
3270
- reconnectCount: this.consecutiveReconnects, // Container reconnect count.
3271
- },
3272
- });
3273
- this._signalTracking.signalsLost = 0;
3274
- this._signalTracking.signalsOutOfOrder = 0;
3275
- this._signalTracking.signalTimestamp = 0;
3276
- this._signalTracking.totalSignalsSentInLatencyWindow = 0;
3277
- }
3278
-
3279
- /**
3280
- * Updates signal telemetry including emitting telemetry events.
3281
- */
3282
- private processSignalForTelemetry(envelope: ISignalEnvelope): void {
3283
- const {
3284
- clientBroadcastSignalSequenceNumber,
3285
- contents: envelopeContents,
3286
- address: envelopeAddress,
3287
- } = envelope;
3288
- if (clientBroadcastSignalSequenceNumber === undefined) {
3289
- return;
3290
- }
3291
-
3292
- if (
3293
- this._signalTracking.trackingSignalSequenceNumber === undefined ||
3294
- this._signalTracking.minimumTrackingSignalSequenceNumber === undefined
3295
- ) {
3296
- return;
3297
- }
3298
-
3299
- if (
3300
- clientBroadcastSignalSequenceNumber >= this._signalTracking.trackingSignalSequenceNumber
3301
- ) {
3302
- // Calculate the number of signals lost and log the event.
3303
- const signalsLost =
3304
- clientBroadcastSignalSequenceNumber -
3305
- this._signalTracking.trackingSignalSequenceNumber;
3306
- if (signalsLost > 0) {
3307
- this._signalTracking.signalsLost += signalsLost;
3308
- this.mc.logger.sendErrorEvent({
3309
- eventName: "SignalLost",
3310
- details: {
3311
- signalsLost, // Number of lost signals detected.
3312
- expectedSequenceNumber: this._signalTracking.trackingSignalSequenceNumber, // The next expected signal sequence number.
3313
- clientBroadcastSignalSequenceNumber, // Actual signal sequence number received.
3314
- },
3315
- });
3316
- }
3317
- // Update the tracking signal sequence number to the next expected signal in the sequence.
3318
- this._signalTracking.trackingSignalSequenceNumber =
3319
- clientBroadcastSignalSequenceNumber + 1;
3320
- } else if (
3321
- // Check if this is a signal in range of interest.
3322
- clientBroadcastSignalSequenceNumber >=
3323
- this._signalTracking.minimumTrackingSignalSequenceNumber
3324
- ) {
3325
- this._signalTracking.signalsOutOfOrder++;
3326
- const details: TelemetryEventPropertyTypeExt = {
3327
- expectedSequenceNumber: this._signalTracking.trackingSignalSequenceNumber, // The next expected signal sequence number.
3328
- clientBroadcastSignalSequenceNumber, // Sequence number of the out of order signal.
3329
- };
3330
- // Only log `contents.type` when address is for container to avoid
3331
- // chance that contents type is customer data.
3332
- if (envelopeAddress === undefined) {
3333
- details.contentsType = envelopeContents.type; // Type of signal that was received out of order.
3334
- }
3335
- this.mc.logger.sendTelemetryEvent({
3336
- eventName: "SignalOutOfOrder",
3337
- details,
3338
- });
3339
- }
3340
- if (
3341
- this._signalTracking.roundTripSignalSequenceNumber !== undefined &&
3342
- clientBroadcastSignalSequenceNumber >= this._signalTracking.roundTripSignalSequenceNumber
3343
- ) {
3344
- if (
3345
- clientBroadcastSignalSequenceNumber ===
3346
- this._signalTracking.roundTripSignalSequenceNumber
3347
- ) {
3348
- // Latency tracked signal has been received.
3349
- // We now log the roundtrip duration of the tracked signal.
3350
- // This telemetry event also logs metrics for broadcast signals
3351
- // sent, lost, and out of order.
3352
- // These metrics are reset after logging the telemetry event.
3353
- this.sendSignalTelemetryEvent();
3354
- }
3355
- this._signalTracking.roundTripSignalSequenceNumber = undefined;
3356
- }
3357
- }
3358
-
3359
3056
  public processSignal(message: ISignalMessage, local: boolean): void {
3360
3057
  const envelope = message.content as ISignalEnvelope;
3361
3058
  const transformed: IInboundSignalMessage = {
@@ -3367,7 +3064,11 @@ export class ContainerRuntime
3367
3064
 
3368
3065
  // Only collect signal telemetry for broadcast messages sent by the current client.
3369
3066
  if (message.clientId === this.clientId) {
3370
- this.processSignalForTelemetry(envelope);
3067
+ this.signalTelemetryManager.trackReceivedSignal(
3068
+ envelope,
3069
+ this.mc.logger,
3070
+ this.consecutiveReconnects,
3071
+ );
3371
3072
  }
3372
3073
 
3373
3074
  if (envelope.address === undefined) {
@@ -3396,8 +3097,8 @@ export class ContainerRuntime
3396
3097
  */
3397
3098
  private flush(resubmittingBatchId?: BatchId): void {
3398
3099
  assert(
3399
- this._orderSequentiallyCalls === 0,
3400
- 0x24c /* "Cannot call `flush()` from `orderSequentially`'s callback" */,
3100
+ !this.batchRunner.running,
3101
+ 0x24c /* "Cannot call `flush()` while manually accumulating a batch (e.g. under orderSequentially) */,
3401
3102
  );
3402
3103
 
3403
3104
  this.outbox.flush(resubmittingBatchId);
@@ -3409,57 +3110,60 @@ export class ContainerRuntime
3409
3110
  */
3410
3111
  public orderSequentially<T>(callback: () => T): T {
3411
3112
  let checkpoint: IBatchCheckpoint | undefined;
3412
- let result: T;
3113
+ const checkpointDirtyState = this.dirtyContainer;
3413
3114
  if (this.mc.config.getBoolean("Fluid.ContainerRuntime.EnableRollback")) {
3414
3115
  // Note: we are not touching any batches other than mainBatch here, for two reasons:
3415
3116
  // 1. It would not help, as other batches are flushed independently from main batch.
3416
3117
  // 2. There is no way to undo process of data store creation, blob creation, ID compressor ops, or other things tracked by other batches.
3417
3118
  checkpoint = this.outbox.getBatchCheckpoints().mainBatch;
3418
3119
  }
3419
- try {
3420
- this._orderSequentiallyCalls++;
3421
- result = callback();
3422
- } catch (error) {
3423
- if (checkpoint) {
3424
- // This will throw and close the container if rollback fails
3425
- try {
3426
- checkpoint.rollback((message: BatchMessage) =>
3427
- this.rollback(message.contents, message.localOpMetadata),
3120
+ const result = this.batchRunner.run(() => {
3121
+ try {
3122
+ return callback();
3123
+ } catch (error) {
3124
+ if (checkpoint) {
3125
+ // This will throw and close the container if rollback fails
3126
+ try {
3127
+ checkpoint.rollback((message: BatchMessage) =>
3128
+ this.rollback(message.contents, message.localOpMetadata),
3129
+ );
3130
+ // reset the dirty state after rollback to what it was before to keep it consistent
3131
+ if (this.dirtyContainer !== checkpointDirtyState) {
3132
+ this.updateDocumentDirtyState(checkpointDirtyState);
3133
+ }
3134
+ } catch (error_) {
3135
+ const error2 = wrapError(error_, (message) => {
3136
+ return DataProcessingError.create(
3137
+ `RollbackError: ${message}`,
3138
+ "checkpointRollback",
3139
+ undefined,
3140
+ ) as DataProcessingError;
3141
+ });
3142
+ this.closeFn(error2);
3143
+ throw error2;
3144
+ }
3145
+ } else {
3146
+ this.closeFn(
3147
+ wrapError(
3148
+ error,
3149
+ (errorMessage) =>
3150
+ new GenericError(
3151
+ `orderSequentially callback exception: ${errorMessage}`,
3152
+ error,
3153
+ {
3154
+ orderSequentiallyCalls: this.batchRunner.runs,
3155
+ },
3156
+ ),
3157
+ ),
3428
3158
  );
3429
- } catch (error_) {
3430
- const error2 = wrapError(error_, (message) => {
3431
- return DataProcessingError.create(
3432
- `RollbackError: ${message}`,
3433
- "checkpointRollback",
3434
- undefined,
3435
- ) as DataProcessingError;
3436
- });
3437
- this.closeFn(error2);
3438
- throw error2;
3439
3159
  }
3440
- } else {
3441
- this.closeFn(
3442
- wrapError(
3443
- error,
3444
- (errorMessage) =>
3445
- new GenericError(
3446
- `orderSequentially callback exception: ${errorMessage}`,
3447
- error,
3448
- {
3449
- orderSequentiallyCalls: this._orderSequentiallyCalls,
3450
- },
3451
- ),
3452
- ),
3453
- );
3454
- }
3455
3160
 
3456
- throw error; // throw the original error for the consumer of the runtime
3457
- } finally {
3458
- this._orderSequentiallyCalls--;
3459
- }
3161
+ throw error; // throw the original error for the consumer of the runtime
3162
+ }
3163
+ });
3460
3164
 
3461
3165
  // We don't flush on TurnBased since we expect all messages in the same JS turn to be part of the same batch
3462
- if (this.flushMode !== FlushMode.TurnBased && this._orderSequentiallyCalls === 0) {
3166
+ if (this.flushMode !== FlushMode.TurnBased && !this.batchRunner.running) {
3463
3167
  this.flush();
3464
3168
  }
3465
3169
  return result;
@@ -3540,7 +3244,7 @@ export class ContainerRuntime
3540
3244
  * Typically ops are batched and later flushed together, but in some cases we want to flush immediately.
3541
3245
  */
3542
3246
  private currentlyBatching(): boolean {
3543
- return this.flushMode !== FlushMode.Immediate || this._orderSequentiallyCalls !== 0;
3247
+ return this.flushMode !== FlushMode.Immediate || this.batchRunner.running;
3544
3248
  }
3545
3249
 
3546
3250
  private readonly _quorum: IQuorumClients;
@@ -3594,59 +3298,6 @@ export class ContainerRuntime
3594
3298
  return true;
3595
3299
  }
3596
3300
 
3597
- private createNewSignalEnvelope(
3598
- address: string | undefined,
3599
- type: string,
3600
- content: unknown,
3601
- ): Omit<ISignalEnvelope, "broadcastSignalSequenceNumber"> {
3602
- const newEnvelope: Omit<ISignalEnvelope, "broadcastSignalSequenceNumber"> = {
3603
- address,
3604
- contents: { type, content },
3605
- };
3606
-
3607
- return newEnvelope;
3608
- }
3609
-
3610
- private submitEnvelopedSignal(envelope: ISignalEnvelope, targetClientId?: string): void {
3611
- const isBroadcastSignal = targetClientId === undefined;
3612
-
3613
- if (isBroadcastSignal) {
3614
- const clientBroadcastSignalSequenceNumber = ++this._signalTracking
3615
- .broadcastSignalSequenceNumber;
3616
- // Stamp with the broadcast signal sequence number.
3617
- envelope.clientBroadcastSignalSequenceNumber = clientBroadcastSignalSequenceNumber;
3618
-
3619
- this._signalTracking.signalsSentSinceLastLatencyMeasurement++;
3620
-
3621
- if (
3622
- this._signalTracking.minimumTrackingSignalSequenceNumber === undefined ||
3623
- this._signalTracking.trackingSignalSequenceNumber === undefined
3624
- ) {
3625
- // Signal monitoring window is undefined
3626
- // Initialize tracking to expect the next signal sent by the connected client.
3627
- this._signalTracking.minimumTrackingSignalSequenceNumber =
3628
- clientBroadcastSignalSequenceNumber;
3629
- this._signalTracking.trackingSignalSequenceNumber =
3630
- clientBroadcastSignalSequenceNumber;
3631
- }
3632
-
3633
- // We should not track the round trip of a new signal in the case we are already tracking one.
3634
- if (
3635
- clientBroadcastSignalSequenceNumber % defaultTelemetrySignalSampleCount === 1 &&
3636
- this._signalTracking.roundTripSignalSequenceNumber === undefined
3637
- ) {
3638
- this._signalTracking.signalTimestamp = Date.now();
3639
- this._signalTracking.roundTripSignalSequenceNumber =
3640
- clientBroadcastSignalSequenceNumber;
3641
- this._signalTracking.totalSignalsSentInLatencyWindow +=
3642
- this._signalTracking.signalsSentSinceLastLatencyMeasurement;
3643
- this._signalTracking.signalsSentSinceLastLatencyMeasurement = 0;
3644
- }
3645
- }
3646
-
3647
- this.submitSignalFn(envelope, targetClientId);
3648
- }
3649
-
3650
3301
  /**
3651
3302
  * Submits the signal to be sent to other clients.
3652
3303
  * @param type - Type of the signal.
@@ -3661,8 +3312,11 @@ export class ContainerRuntime
3661
3312
  */
3662
3313
  public submitSignal(type: string, content: unknown, targetClientId?: string): void {
3663
3314
  this.verifyNotClosed();
3664
- const envelope = this.createNewSignalEnvelope(undefined /* address */, type, content);
3665
- return this.submitEnvelopedSignal(envelope, targetClientId);
3315
+ const envelope = createNewSignalEnvelope(undefined /* address */, type, content);
3316
+ if (targetClientId === undefined) {
3317
+ this.signalTelemetryManager.applyTrackingToBroadcastSignalEnvelope(envelope);
3318
+ }
3319
+ this.submitSignalFn(envelope, targetClientId);
3666
3320
  }
3667
3321
 
3668
3322
  public setAttachState(attachState: AttachState.Attaching | AttachState.Attached): void {
@@ -3911,13 +3565,12 @@ export class ContainerRuntime
3911
3565
  * Returns the type of the GC node. Currently, there are nodes that belong to the root ("/"), data stores or
3912
3566
  * blob manager.
3913
3567
  */
3914
- // eslint-disable-next-line import/no-deprecated
3568
+
3915
3569
  public getNodeType(nodePath: string): GCNodeType {
3916
3570
  if (isBlobPath(nodePath)) {
3917
- // eslint-disable-next-line import/no-deprecated
3918
3571
  return GCNodeType.Blob;
3919
3572
  }
3920
- // eslint-disable-next-line import/no-deprecated
3573
+
3921
3574
  return this.channelCollection.getGCNodeType(nodePath) ?? GCNodeType.Other;
3922
3575
  }
3923
3576
 
@@ -3933,13 +3586,12 @@ export class ContainerRuntime
3933
3586
  }
3934
3587
 
3935
3588
  switch (this.getNodeType(nodePath)) {
3936
- // eslint-disable-next-line import/no-deprecated
3937
3589
  case GCNodeType.Blob: {
3938
3590
  return [blobManagerBasePath];
3939
3591
  }
3940
- // eslint-disable-next-line import/no-deprecated
3592
+
3941
3593
  case GCNodeType.DataStore:
3942
- // eslint-disable-next-line import/no-deprecated
3594
+
3943
3595
  case GCNodeType.SubDataStore: {
3944
3596
  return this.channelCollection.getDataStorePackagePath(nodePath);
3945
3597
  }
@@ -3991,7 +3643,6 @@ export class ContainerRuntime
3991
3643
  fullGC?: boolean;
3992
3644
  },
3993
3645
  telemetryContext?: ITelemetryContext,
3994
- // eslint-disable-next-line import/no-deprecated
3995
3646
  ): Promise<IGCStats | undefined> {
3996
3647
  return this.garbageCollector.collectGarbage(options, telemetryContext);
3997
3648
  }
@@ -4034,7 +3685,7 @@ export class ContainerRuntime
4034
3685
  * op processing, updating SummarizerNode state tracking, and garbage collection.
4035
3686
  * @param options - options controlling how the summary is generated or submitted
4036
3687
  */
4037
- // eslint-disable-next-line import/no-deprecated
3688
+
4038
3689
  public async submitSummary(options: ISubmitSummaryOptions): Promise<SubmitSummaryResult> {
4039
3690
  const {
4040
3691
  cancellationToken,
@@ -4662,8 +4313,8 @@ export class ContainerRuntime
4662
4313
 
4663
4314
  default: {
4664
4315
  assert(
4665
- this._orderSequentiallyCalls > 0,
4666
- 0x587 /* Unreachable unless running under orderSequentially */,
4316
+ this.batchRunner.running,
4317
+ 0x587 /* Unreachable unless manually accumulating a batch */,
4667
4318
  );
4668
4319
  break;
4669
4320
  }
@@ -4703,7 +4354,7 @@ export class ContainerRuntime
4703
4354
  * for correlation to detect container forking.
4704
4355
  */
4705
4356
  private reSubmitBatch(batch: PendingMessageResubmitData[], batchId: BatchId): void {
4706
- this.orderSequentially(() => {
4357
+ this.batchRunner.run(() => {
4707
4358
  for (const message of batch) {
4708
4359
  this.reSubmit(message);
4709
4360
  }
@@ -4800,7 +4451,7 @@ export class ContainerRuntime
4800
4451
  /**
4801
4452
  * Implementation of ISummarizerInternalsProvider.refreshLatestSummaryAck
4802
4453
  */
4803
- // eslint-disable-next-line import/no-deprecated
4454
+
4804
4455
  public async refreshLatestSummaryAck(options: IRefreshSummaryAckOptions): Promise<void> {
4805
4456
  const { proposalHandle, ackHandle, summaryRefSeq, summaryLogger } = options;
4806
4457
  // proposalHandle is always passed from RunningSummarizer.
@@ -4951,8 +4602,8 @@ export class ContainerRuntime
4951
4602
  public getPendingLocalState(props?: IGetPendingLocalStateProps): unknown {
4952
4603
  this.verifyNotClosed();
4953
4604
 
4954
- if (this._orderSequentiallyCalls !== 0) {
4955
- throw new UsageError("can't get state during orderSequentially");
4605
+ if (this.batchRunner.running) {
4606
+ throw new UsageError("can't get state while manually accumulating a batch");
4956
4607
  }
4957
4608
  this.imminentClosure ||= props?.notifyImminentClosure ?? false;
4958
4609
 
@@ -5032,34 +4683,20 @@ export class ContainerRuntime
5032
4683
  }
5033
4684
  }
5034
4685
 
5035
- /**
5036
- * Forms a function that will create and retrieve a Summarizer.
5037
- */
5038
- private formCreateSummarizerFn(loader: ILoader) {
5039
- return async () => {
5040
- return createSummarizer(loader, `/${summarizerRequestUrl}`);
5041
- };
5042
- }
5043
-
5044
- private validateSummaryHeuristicConfiguration(
5045
- configuration: ISummaryConfigurationHeuristics,
5046
- ): void {
5047
- // eslint-disable-next-line no-restricted-syntax
5048
- for (const prop in configuration) {
5049
- if (typeof configuration[prop] === "number" && configuration[prop] < 0) {
5050
- throw new UsageError(
5051
- `Summary heuristic configuration property "${prop}" cannot be less than 0`,
5052
- );
5053
- }
5054
- }
5055
- if (configuration.minIdleTime > configuration.maxIdleTime) {
5056
- throw new UsageError(
5057
- `"minIdleTime" [${configuration.minIdleTime}] cannot be greater than "maxIdleTime" [${configuration.maxIdleTime}]`,
5058
- );
5059
- }
5060
- }
5061
-
5062
4686
  private get groupedBatchingEnabled(): boolean {
5063
4687
  return this.sessionSchema.opGroupingEnabled === true;
5064
4688
  }
5065
4689
  }
4690
+
4691
+ export function createNewSignalEnvelope(
4692
+ address: string | undefined,
4693
+ type: string,
4694
+ content: unknown,
4695
+ ): Omit<ISignalEnvelope, "broadcastSignalSequenceNumber"> {
4696
+ const newEnvelope: Omit<ISignalEnvelope, "broadcastSignalSequenceNumber"> = {
4697
+ address,
4698
+ contents: { type, content },
4699
+ };
4700
+
4701
+ return newEnvelope;
4702
+ }