@fluidframework/container-runtime 2.0.0-internal.6.4.0 → 2.0.0-internal.7.1.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 (237) hide show
  1. package/CHANGELOG.md +111 -0
  2. package/api-extractor.json +13 -1
  3. package/api-report/container-runtime.api.md +799 -0
  4. package/dist/blobManager.d.ts +1 -1
  5. package/dist/blobManager.d.ts.map +1 -1
  6. package/dist/blobManager.js +7 -7
  7. package/dist/blobManager.js.map +1 -1
  8. package/dist/connectionTelemetry.d.ts.map +1 -1
  9. package/dist/connectionTelemetry.js +75 -42
  10. package/dist/connectionTelemetry.js.map +1 -1
  11. package/dist/container-runtime-alpha.d.ts +1554 -0
  12. package/dist/container-runtime-beta.d.ts +1554 -0
  13. package/dist/container-runtime-public.d.ts +1554 -0
  14. package/dist/container-runtime.d.ts +1611 -0
  15. package/dist/containerHandleContext.js +3 -3
  16. package/dist/containerHandleContext.js.map +1 -1
  17. package/dist/containerRuntime.d.ts +28 -24
  18. package/dist/containerRuntime.d.ts.map +1 -1
  19. package/dist/containerRuntime.js +277 -256
  20. package/dist/containerRuntime.js.map +1 -1
  21. package/dist/dataStore.js +9 -9
  22. package/dist/dataStore.js.map +1 -1
  23. package/dist/dataStoreContext.d.ts +1 -3
  24. package/dist/dataStoreContext.d.ts.map +1 -1
  25. package/dist/dataStoreContext.js +54 -58
  26. package/dist/dataStoreContext.js.map +1 -1
  27. package/dist/dataStoreRegistry.js +3 -3
  28. package/dist/dataStoreRegistry.js.map +1 -1
  29. package/dist/deltaManagerProxyBase.js +4 -4
  30. package/dist/deltaManagerProxyBase.js.map +1 -1
  31. package/dist/deltaManagerSummarizerProxy.js +6 -6
  32. package/dist/deltaManagerSummarizerProxy.js.map +1 -1
  33. package/dist/deltaScheduler.js.map +1 -1
  34. package/dist/error.d.ts.map +1 -1
  35. package/dist/error.js.map +1 -1
  36. package/dist/gc/garbageCollection.js +13 -13
  37. package/dist/gc/garbageCollection.js.map +1 -1
  38. package/dist/gc/gcDefinitions.d.ts +4 -15
  39. package/dist/gc/gcDefinitions.d.ts.map +1 -1
  40. package/dist/gc/gcDefinitions.js.map +1 -1
  41. package/dist/gc/gcTelemetry.d.ts +1 -1
  42. package/dist/gc/gcTelemetry.d.ts.map +1 -1
  43. package/dist/gc/gcUnreferencedStateTracker.js +3 -3
  44. package/dist/gc/gcUnreferencedStateTracker.js.map +1 -1
  45. package/dist/id-compressor/appendOnlySortedMap.js.map +1 -1
  46. package/dist/id-compressor/idCompressor.js.map +1 -1
  47. package/dist/id-compressor/identifiers.d.ts +3 -3
  48. package/dist/id-compressor/identifiers.d.ts.map +1 -1
  49. package/dist/index.d.ts +1 -1
  50. package/dist/index.d.ts.map +1 -1
  51. package/dist/index.js +2 -1
  52. package/dist/index.js.map +1 -1
  53. package/dist/messageTypes.d.ts +17 -17
  54. package/dist/messageTypes.d.ts.map +1 -1
  55. package/dist/messageTypes.js +1 -1
  56. package/dist/messageTypes.js.map +1 -1
  57. package/dist/opLifecycle/batchManager.js +6 -6
  58. package/dist/opLifecycle/batchManager.js.map +1 -1
  59. package/dist/opLifecycle/definitions.d.ts +2 -2
  60. package/dist/opLifecycle/definitions.d.ts.map +1 -1
  61. package/dist/opLifecycle/outbox.d.ts.map +1 -1
  62. package/dist/opLifecycle/outbox.js +7 -2
  63. package/dist/opLifecycle/outbox.js.map +1 -1
  64. package/dist/packageVersion.d.ts +1 -1
  65. package/dist/packageVersion.js +1 -1
  66. package/dist/packageVersion.js.map +1 -1
  67. package/dist/pendingStateManager.d.ts +3 -19
  68. package/dist/pendingStateManager.d.ts.map +1 -1
  69. package/dist/pendingStateManager.js +23 -40
  70. package/dist/pendingStateManager.js.map +1 -1
  71. package/dist/scheduleManager.js +6 -2
  72. package/dist/scheduleManager.js.map +1 -1
  73. package/dist/summary/orderedClientElection.d.ts +3 -3
  74. package/dist/summary/orderedClientElection.d.ts.map +1 -1
  75. package/dist/summary/orderedClientElection.js +54 -54
  76. package/dist/summary/orderedClientElection.js.map +1 -1
  77. package/dist/summary/runWhileConnectedCoordinator.js +6 -6
  78. package/dist/summary/runWhileConnectedCoordinator.js.map +1 -1
  79. package/dist/summary/runningSummarizer.js +37 -37
  80. package/dist/summary/runningSummarizer.js.map +1 -1
  81. package/dist/summary/summarizer.d.ts +1 -0
  82. package/dist/summary/summarizer.d.ts.map +1 -1
  83. package/dist/summary/summarizer.js +17 -8
  84. package/dist/summary/summarizer.js.map +1 -1
  85. package/dist/summary/summarizerClientElection.js +6 -6
  86. package/dist/summary/summarizerClientElection.js.map +1 -1
  87. package/dist/summary/summarizerHeuristics.js +9 -9
  88. package/dist/summary/summarizerHeuristics.js.map +1 -1
  89. package/dist/summary/summarizerNode/summarizerNode.js +7 -7
  90. package/dist/summary/summarizerNode/summarizerNode.js.map +1 -1
  91. package/dist/summary/summarizerNode/summarizerNodeUtils.d.ts +1 -1
  92. package/dist/summary/summarizerNode/summarizerNodeUtils.d.ts.map +1 -1
  93. package/dist/summary/summarizerNode/summarizerNodeUtils.js +3 -3
  94. package/dist/summary/summarizerNode/summarizerNodeUtils.js.map +1 -1
  95. package/dist/summary/summarizerNode/summarizerNodeWithGc.d.ts +2 -2
  96. package/dist/summary/summarizerNode/summarizerNodeWithGc.d.ts.map +1 -1
  97. package/dist/summary/summarizerTypes.d.ts +12 -12
  98. package/dist/summary/summarizerTypes.d.ts.map +1 -1
  99. package/dist/summary/summaryCollection.d.ts +2 -2
  100. package/dist/summary/summaryCollection.d.ts.map +1 -1
  101. package/dist/summary/summaryCollection.js +22 -21
  102. package/dist/summary/summaryCollection.js.map +1 -1
  103. package/dist/summary/summaryFormat.d.ts +5 -5
  104. package/dist/summary/summaryFormat.d.ts.map +1 -1
  105. package/dist/summary/summaryGenerator.d.ts +3 -3
  106. package/dist/summary/summaryGenerator.d.ts.map +1 -1
  107. package/dist/summary/summaryGenerator.js.map +1 -1
  108. package/dist/summary/summaryManager.d.ts +2 -2
  109. package/dist/summary/summaryManager.d.ts.map +1 -1
  110. package/dist/summary/summaryManager.js +10 -10
  111. package/dist/summary/summaryManager.js.map +1 -1
  112. package/dist/throttler.js +16 -16
  113. package/dist/throttler.js.map +1 -1
  114. package/dist/tsdoc-metadata.json +1 -1
  115. package/lib/blobManager.d.ts +1 -1
  116. package/lib/blobManager.d.ts.map +1 -1
  117. package/lib/blobManager.js +7 -7
  118. package/lib/blobManager.js.map +1 -1
  119. package/lib/connectionTelemetry.d.ts.map +1 -1
  120. package/lib/connectionTelemetry.js +76 -43
  121. package/lib/connectionTelemetry.js.map +1 -1
  122. package/lib/containerHandleContext.js +3 -3
  123. package/lib/containerHandleContext.js.map +1 -1
  124. package/lib/containerRuntime.d.ts +28 -24
  125. package/lib/containerRuntime.d.ts.map +1 -1
  126. package/lib/containerRuntime.js +268 -252
  127. package/lib/containerRuntime.js.map +1 -1
  128. package/lib/dataStore.js +9 -9
  129. package/lib/dataStore.js.map +1 -1
  130. package/lib/dataStoreContext.d.ts +1 -3
  131. package/lib/dataStoreContext.d.ts.map +1 -1
  132. package/lib/dataStoreContext.js +54 -58
  133. package/lib/dataStoreContext.js.map +1 -1
  134. package/lib/dataStoreRegistry.js +3 -3
  135. package/lib/dataStoreRegistry.js.map +1 -1
  136. package/lib/deltaManagerProxyBase.js +4 -4
  137. package/lib/deltaManagerProxyBase.js.map +1 -1
  138. package/lib/deltaManagerSummarizerProxy.js +6 -6
  139. package/lib/deltaManagerSummarizerProxy.js.map +1 -1
  140. package/lib/deltaScheduler.js.map +1 -1
  141. package/lib/error.d.ts.map +1 -1
  142. package/lib/error.js.map +1 -1
  143. package/lib/gc/garbageCollection.js +13 -13
  144. package/lib/gc/garbageCollection.js.map +1 -1
  145. package/lib/gc/gcDefinitions.d.ts +4 -15
  146. package/lib/gc/gcDefinitions.d.ts.map +1 -1
  147. package/lib/gc/gcDefinitions.js.map +1 -1
  148. package/lib/gc/gcTelemetry.d.ts +1 -1
  149. package/lib/gc/gcTelemetry.d.ts.map +1 -1
  150. package/lib/gc/gcUnreferencedStateTracker.js +3 -3
  151. package/lib/gc/gcUnreferencedStateTracker.js.map +1 -1
  152. package/lib/id-compressor/appendOnlySortedMap.js.map +1 -1
  153. package/lib/id-compressor/idCompressor.js.map +1 -1
  154. package/lib/id-compressor/identifiers.d.ts +3 -3
  155. package/lib/id-compressor/identifiers.d.ts.map +1 -1
  156. package/lib/index.d.ts +1 -1
  157. package/lib/index.d.ts.map +1 -1
  158. package/lib/index.js +1 -1
  159. package/lib/index.js.map +1 -1
  160. package/lib/messageTypes.d.ts +17 -17
  161. package/lib/messageTypes.d.ts.map +1 -1
  162. package/lib/opLifecycle/batchManager.js +6 -6
  163. package/lib/opLifecycle/batchManager.js.map +1 -1
  164. package/lib/opLifecycle/definitions.d.ts +2 -2
  165. package/lib/opLifecycle/definitions.d.ts.map +1 -1
  166. package/lib/opLifecycle/outbox.d.ts.map +1 -1
  167. package/lib/opLifecycle/outbox.js +7 -2
  168. package/lib/opLifecycle/outbox.js.map +1 -1
  169. package/lib/packageVersion.d.ts +1 -1
  170. package/lib/packageVersion.js +1 -1
  171. package/lib/packageVersion.js.map +1 -1
  172. package/lib/pendingStateManager.d.ts +3 -19
  173. package/lib/pendingStateManager.d.ts.map +1 -1
  174. package/lib/pendingStateManager.js +23 -40
  175. package/lib/pendingStateManager.js.map +1 -1
  176. package/lib/scheduleManager.js +6 -2
  177. package/lib/scheduleManager.js.map +1 -1
  178. package/lib/summary/orderedClientElection.d.ts +3 -3
  179. package/lib/summary/orderedClientElection.d.ts.map +1 -1
  180. package/lib/summary/orderedClientElection.js +54 -54
  181. package/lib/summary/orderedClientElection.js.map +1 -1
  182. package/lib/summary/runWhileConnectedCoordinator.js +6 -6
  183. package/lib/summary/runWhileConnectedCoordinator.js.map +1 -1
  184. package/lib/summary/runningSummarizer.js +37 -37
  185. package/lib/summary/runningSummarizer.js.map +1 -1
  186. package/lib/summary/summarizer.d.ts +1 -0
  187. package/lib/summary/summarizer.d.ts.map +1 -1
  188. package/lib/summary/summarizer.js +18 -9
  189. package/lib/summary/summarizer.js.map +1 -1
  190. package/lib/summary/summarizerClientElection.js +6 -6
  191. package/lib/summary/summarizerClientElection.js.map +1 -1
  192. package/lib/summary/summarizerHeuristics.js +9 -9
  193. package/lib/summary/summarizerHeuristics.js.map +1 -1
  194. package/lib/summary/summarizerNode/summarizerNode.js +7 -7
  195. package/lib/summary/summarizerNode/summarizerNode.js.map +1 -1
  196. package/lib/summary/summarizerNode/summarizerNodeUtils.d.ts +1 -1
  197. package/lib/summary/summarizerNode/summarizerNodeUtils.d.ts.map +1 -1
  198. package/lib/summary/summarizerNode/summarizerNodeUtils.js +3 -3
  199. package/lib/summary/summarizerNode/summarizerNodeUtils.js.map +1 -1
  200. package/lib/summary/summarizerNode/summarizerNodeWithGc.d.ts +2 -2
  201. package/lib/summary/summarizerNode/summarizerNodeWithGc.d.ts.map +1 -1
  202. package/lib/summary/summarizerTypes.d.ts +12 -12
  203. package/lib/summary/summarizerTypes.d.ts.map +1 -1
  204. package/lib/summary/summaryCollection.d.ts +2 -2
  205. package/lib/summary/summaryCollection.d.ts.map +1 -1
  206. package/lib/summary/summaryCollection.js +22 -21
  207. package/lib/summary/summaryCollection.js.map +1 -1
  208. package/lib/summary/summaryFormat.d.ts +5 -5
  209. package/lib/summary/summaryFormat.d.ts.map +1 -1
  210. package/lib/summary/summaryGenerator.d.ts +3 -3
  211. package/lib/summary/summaryGenerator.d.ts.map +1 -1
  212. package/lib/summary/summaryGenerator.js.map +1 -1
  213. package/lib/summary/summaryManager.d.ts +2 -2
  214. package/lib/summary/summaryManager.d.ts.map +1 -1
  215. package/lib/summary/summaryManager.js +9 -9
  216. package/lib/summary/summaryManager.js.map +1 -1
  217. package/lib/throttler.js +16 -16
  218. package/lib/throttler.js.map +1 -1
  219. package/package.json +27 -27
  220. package/src/blobManager.ts +1 -1
  221. package/src/connectionTelemetry.ts +97 -52
  222. package/src/containerRuntime.ts +96 -73
  223. package/src/dataStore.ts +1 -1
  224. package/src/dataStoreContext.ts +1 -6
  225. package/src/error.ts +4 -1
  226. package/src/gc/gcDefinitions.ts +3 -15
  227. package/src/gc/gcEarlyAdoption.md +1 -1
  228. package/src/index.ts +1 -0
  229. package/src/opLifecycle/README.md +53 -28
  230. package/src/opLifecycle/outbox.ts +3 -0
  231. package/src/packageVersion.ts +1 -1
  232. package/src/pendingStateManager.ts +8 -46
  233. package/src/scheduleManager.ts +2 -0
  234. package/src/summary/summarizer.ts +20 -7
  235. package/src/summary/summaryCollection.ts +1 -0
  236. package/src/summary/summaryGenerator.ts +3 -3
  237. package/src/summary/summaryManager.ts +2 -2
@@ -740,11 +740,6 @@ export abstract class FluidDataStoreContext
740
740
  this.makeLocallyVisibleFn();
741
741
  }
742
742
 
743
- /** @deprecated - To be replaced by calling makeLocallyVisible directly */
744
- public bindToContext() {
745
- this.makeLocallyVisibleFn();
746
- }
747
-
748
743
  protected bindRuntime(channel: IFluidDataStoreChannel) {
749
744
  if (this.channel) {
750
745
  throw new Error("Runtime already bound");
@@ -1206,7 +1201,7 @@ export class LocalDetachedFluidDataStoreContext
1206
1201
  // of data store factories tends to construct the data object (at least kick off an async method that returns
1207
1202
  // it); that code moved to the entryPoint initialization function, so we want to ensure it still executes
1208
1203
  // before the data store is attached.
1209
- await dataStoreChannel.entryPoint?.get();
1204
+ await dataStoreChannel.entryPoint.get();
1210
1205
 
1211
1206
  if (await this.isRoot()) {
1212
1207
  dataStoreChannel.makeVisibleAndAttachGraph();
package/src/error.ts CHANGED
@@ -12,7 +12,10 @@ import { IFluidErrorBase, LoggingError } from "@fluidframework/telemetry-utils";
12
12
  export class ClientSessionExpiredError extends LoggingError implements IFluidErrorBase {
13
13
  readonly errorType = ContainerErrorTypes.clientSessionExpiredError;
14
14
 
15
- constructor(message: string, readonly expiryMs: number) {
15
+ constructor(
16
+ message: string,
17
+ readonly expiryMs: number,
18
+ ) {
16
19
  super(message, { timeoutMs: expiryMs });
17
20
  }
18
21
  }
@@ -165,7 +165,7 @@ export const GCNodeType = {
165
165
  // Nodes that are neither of the above. For example, root node.
166
166
  Other: "Other",
167
167
  };
168
- export type GCNodeType = typeof GCNodeType[keyof typeof GCNodeType];
168
+ export type GCNodeType = (typeof GCNodeType)[keyof typeof GCNodeType];
169
169
 
170
170
  /**
171
171
  * Defines the APIs for the runtime object to be passed to the garbage collector.
@@ -267,24 +267,12 @@ export interface IGCRuntimeOptions {
267
267
  * GC has mark phase and sweep phase. In mark phase, unreferenced objects are identified
268
268
  * and marked as such in the summary. This option enables the mark phase.
269
269
  * In sweep phase, unreferenced objects are eventually deleted from the container if they meet certain conditions.
270
- * Sweep phase can be enabled via the "sweepAllowed" option.
270
+ * Sweep phase can be enabled using the "gcSweepGeneration" option.
271
271
  *
272
272
  * Note: This setting is persisted in the container's summary and cannot be changed.
273
273
  */
274
274
  gcAllowed?: boolean;
275
275
 
276
- /**
277
- * @deprecated - @see gcSweepGenerationOptionName and @see GCFeatureMatrix.sweepGeneration
278
- *
279
- * Flag that if true, enables GC's sweep phase for a new container.
280
- *
281
- * This will allow GC to eventually delete unreferenced objects from the container.
282
- * This flag should only be set to true if "gcAllowed" is true.
283
- *
284
- * Note: This setting is persisted in the container's summary and cannot be changed.
285
- */
286
- sweepAllowed?: boolean;
287
-
288
276
  /**
289
277
  * Flag that if true, will disable garbage collection for the session.
290
278
  * Can be used to disable running GC on containers where it is allowed via the gcAllowed option.
@@ -372,7 +360,7 @@ export const UnreferencedState = {
372
360
  /** The node is ready to be deleted by the sweep phase. */
373
361
  SweepReady: "SweepReady",
374
362
  } as const;
375
- export type UnreferencedState = typeof UnreferencedState[keyof typeof UnreferencedState];
363
+ export type UnreferencedState = (typeof UnreferencedState)[keyof typeof UnreferencedState];
376
364
 
377
365
  /**
378
366
  * Represents the result of a GC run.
@@ -78,7 +78,7 @@ For this to work, you must disable the `Fluid.GarbageCollection.ThrowOnTombstone
78
78
 
79
79
  When a Tombstoned object (via `handle.get()`) fails to load, the 404 response error object has an `underlyingResponseHeaders` with the
80
80
  `isTombstoned` flag set to true: i.e. `error.underlyingResponseHeaders?.isTombstoned === true`. In this case,
81
- you may turn around and use `IContainerRuntime.resolveHandle` with `allowTombstone: true` in `IRequest.headers` to request
81
+ you may turn around and use `IContainerRuntimeWithResolveHandle_Deprecated.resolveHandle` with `allowTombstone: true` in `IRequest.headers` to request
82
82
  the object again - this time it will succeed.
83
83
 
84
84
  To be very clear once again - This path uses deprecated APIs (`resolveHandle`) and comes with no guarantees of support.
package/src/index.ts CHANGED
@@ -23,6 +23,7 @@ export {
23
23
  DefaultSummaryConfiguration,
24
24
  ICompressionRuntimeOptions,
25
25
  CompressionAlgorithms,
26
+ TEST_requestSummarizer,
26
27
  } from "./containerRuntime";
27
28
  export {
28
29
  ContainerMessageType,
@@ -1,5 +1,19 @@
1
1
  # Configs and feature gates for solving the 1MB limit.
2
2
 
3
+ ## Table of contents
4
+
5
+ - [Introduction](#introduction)
6
+ - [How batching works](#how-batching-works)
7
+ - [Compression](#compression)
8
+ - [Grouped batching](#grouped-batching)
9
+ - [Risks](#risks)
10
+ - [Chunking for compression](#chunking-for-compression)
11
+ - [Disabling in case of emergency](#disabling-in-case-of-emergency)
12
+ - [Example configs](#example-configs)
13
+ - [Note about performance and latency](#note-about-performance-and-latency)
14
+ - [How it works](#how-it-works)
15
+ - [How grouped batching works](#how-grouped-batching-works)
16
+
3
17
  ## Introduction
4
18
 
5
19
  There is a current limitation regarding the size of the payload a Fluid client can send and receive. [The limit is 1MB per payload](https://github.com/microsoft/FluidFramework/issues/9023) and it is currently enforced explicitly with the `BatchTooLarge` error which closes the container.
@@ -8,17 +22,35 @@ There are two features which can be used to work around this size limit, batch c
8
22
 
9
23
  By default, the runtime is configured with a max batch size of `716800` bytes, which is lower than the 1MB limit. The reason for the lower value is to account for possible overhead from the op envelope and metadata.
10
24
 
11
- ## Table of contents
25
+ ### How batching works
12
26
 
13
- - [Introduction](#introduction)
14
- - [Compression](#compression)
15
- - [Grouped batching](#grouped-batching)
16
- - [Risks](#risks)
17
- - [Chunking for compression](#chunking-for-compression)
18
- - [Disabling in case of emergency](#disabling-in-case-of-emergency)
19
- - [Example configs](#example-configs)
20
- - [How it works](#how-it-works)
21
- - [How grouped batching works](#how-grouped-batching-works)
27
+ Batching in the context of Fluid ops is a way in which the framework accumulates and applies ops. A batch is a group of ops accumulated within a single JS turn, which will be broadcasted in the same order to all the other connected clients and applied synchronously. Additional logic and validation ensure that batches are never interleaved, nested or interrupted and they are processed in isolation without interleaving of ops from other clients.
28
+
29
+ The way batches are formed is governed by the `FlushMode` setting of the `ContainerRuntimeOptions` and it is immutable for the entire lifetime of the runtime and subsequently the container.
30
+
31
+ ```
32
+ export enum FlushMode {
33
+ /**
34
+ * In Immediate flush mode the runtime will immediately send all operations to the driver layer.
35
+ */
36
+ Immediate,
37
+
38
+ /**
39
+ * When in TurnBased flush mode the runtime will buffer operations in the current turn and send them as a single
40
+ * batch at the end of the turn. The flush call on the runtime can be used to force send the current batch.
41
+ */
42
+ TurnBased,
43
+ }
44
+ ```
45
+
46
+ What this means is that `FlushMode.Immediate` will send each op in its own payload to the server, while `FlushMode.TurnBased` will accumulate all ops in a single JS turn and send them together in the same payload. Technically, `FlushMode.Immediate` can be simulated with `FlushMode.TurnBased` by interrupting the JS turn after producing only one op (for example by pausing the execution to wait on a promise). Therefore, for all intents and purposes, `FlushMode.Immediate` enables all batches to have only one op.
47
+
48
+ **By default, Fluid uses `FlushMode.TurnBased`** as:
49
+
50
+ - it is more efficient from an I/O perspective (batching ops overall decrease the number of payloads sent to the server)
51
+ - reduces concurrency related bugs, as it ensures that all ops generated within the same JS turn are also applied by all other clients within a single JS turn. Clients using the same pattern can safely assume ops will be applied exactly as they are observed locally. The alternative would be for ops to be both produced and applied with interruptions (which may involve processing input or rendering), invalidating the state based off which the changes were produced.
52
+
53
+ As `FlushMode.TurnBased` accumulates ops, it is the most vulnerable to run into the 1MB socket limit.
22
54
 
23
55
  ## Compression
24
56
 
@@ -29,6 +61,8 @@ By default, the runtime is configured with a max batch size of `716800` bytes, w
29
61
  - `minimumBatchSizeInBytes` – the minimum size of the batch for which compression should kick in. If the payload is too small, compression may not yield too many benefits. To target the original 1MB issue, a good value here would be to match the default maxBatchSizeInBytes (972800), however, experimentally, a good lower value could be at around 614400 bytes. Setting this value to `Number.POSITIVE_INFINITY` will disable compression.
30
62
  - `compressionAlgorithm` – currently, only `lz4` is supported.
31
63
 
64
+ Compression is relevant for both `FlushMode.TurnBased` and `FlushMode.Immediate` as it only targets the contents of the ops and not the number of ops in a batch. Compression is opaque to the server and implementations of the Fluid protocol do not need to alter their behavior to support this client feature.
65
+
32
66
  ## Grouped batching
33
67
 
34
68
  **Note: This feature is currently considered experimental and is not ready for production usage.**
@@ -71,6 +105,8 @@ If all prerequisites in the previous section are met, enabling the feature can b
71
105
 
72
106
  In case of emergency grouped batching can be disabled at runtime, using feature gates. If `"Fluid.ContainerRuntime.DisableGroupedBatching"` is set to `true`, it will disable grouped batching if enabled from `IContainerRuntimeOptions` in the code.
73
107
 
108
+ Grouped batching is only relevant for `FlushMode.TurnBased` as it only targets the number of ops in a batch. Grouped batching is opaque to the server and implementations of the Fluid protocol do not need to alter their behavior to support this client feature.
109
+
74
110
  ## Chunking for compression
75
111
 
76
112
  **Op chunking for compression targets payloads which exceed the max batch size after compression.** So, only payloads which are already compressed. By default, the feature is enabled.
@@ -79,6 +115,8 @@ The `IContainerRuntimeOptions.chunkSizeInBytes` property is the only configurati
79
115
 
80
116
  This config would govern chunking compressed batches only. We will not be enabling chunking across all types of ops/batches but **only when compression is enabled and when the batch is compressed**, and its payload size is more than `IContainerRuntimeOptions.chunkSizeInBytes`.
81
117
 
118
+ Chunking is relevant for both `FlushMode.TurnBased` and `FlushMode.Immediate` as it only targets the contents of the ops and not the number of ops in a batch. Chunking is opaque to the server and implementations of the Fluid protocol do not need to alter their behavior to support this client feature.
119
+
82
120
  ## Disabling in case of emergency
83
121
 
84
122
  If the features are enabled using the configs, they can be disabled at runtime via feature gates as following:
@@ -102,32 +140,19 @@ By default, the runtime is configured with the following values related to compr
102
140
      }
103
141
  ```
104
142
 
105
- To use compression but disable chunking:
143
+ To enable grouped batching, use the following property:
106
144
 
107
145
  ```
108
146
  const runtimeOptions: IContainerRuntimeOptions = {
109
- chunkSizeInBytes: Number.POSITIVE_INFINITY,
147
+ enableGroupedBatching: true,
110
148
      }
111
149
  ```
112
150
 
113
- To disable compression (will also disable chunking, as chunking works only for compressed batches):
114
-
115
- ```
116
- const runtimeOptions: IContainerRuntimeOptions = {
117
- compressionOptions: {
118
- minimumBatchSizeInBytes: Number.POSITIVE_INFINITY,
119
- compressionAlgorithm: CompressionAlgorithms.lz4,
120
- },
121
-     }
122
- ```
151
+ ## Note about performance and latency
123
152
 
124
- To enable grouped batching:
153
+ In terms of performance and impact on latency, the results greatly depend on payload size, payload structure, network speed and CPU speed. Therefore, customers must perform the required measurements and adjust the settings according to their scenarios.
125
154
 
126
- ```
127
- const runtimeOptions: IContainerRuntimeOptions = {
128
- enableGroupedBatching: true,
129
-     }
130
- ```
155
+ In general, compression offers a trade-off between higher compute costs, lower bandwidth consumption and lower storage requirements, while chunking slightly increases latency due to the overhead of splitting an op, sending the chunks and reconstructing them on each client. Grouped batching heavily decreases the number of ops observed by the server and slightly decreases the bandwidth requirements as it merges all the ops in a batch into a single op and also eliminates the op envelope overhead.
131
156
 
132
157
  ## How it works
133
158
 
@@ -65,10 +65,13 @@ export interface IOutboxParameters {
65
65
  export function getLongStack<T>(action: () => T, length: number = 50): T {
66
66
  const errorObj = Error as any;
67
67
  if (
68
+ /* eslint-disable @typescript-eslint/prefer-nullish-coalescing */
69
+ // ?? is not logically equivalent when the first clause returns false.
68
70
  (
69
71
  Object.getOwnPropertyDescriptor(errorObj, "stackTraceLimit") ||
70
72
  Object.getOwnPropertyDescriptor(Object.getPrototypeOf(errorObj), "stackTraceLimit")
71
73
  )?.writable !== true
74
+ /* eslint-enable @typescript-eslint/prefer-nullish-coalescing */
72
75
  ) {
73
76
  return action();
74
77
  }
@@ -6,4 +6,4 @@
6
6
  */
7
7
 
8
8
  export const pkgName = "@fluidframework/container-runtime";
9
- export const pkgVersion = "2.0.0-internal.6.4.0";
9
+ export const pkgVersion = "2.0.0-internal.7.1.0";
@@ -15,24 +15,11 @@ import { ContainerMessageType, InboundSequencedContainerRuntimeMessage } from ".
15
15
  import { pkgVersion } from "./packageVersion";
16
16
  import { IBatchMetadata } from "./metadata";
17
17
 
18
- /**
19
- * ! TODO: Remove this interface in "2.0.0-internal.7.0.0" once we only read IPendingMessageNew (AB#4763)
20
- */
21
- export interface IPendingMessageOld {
22
- type: "message";
23
- messageType: ContainerMessageType;
24
- clientSequenceNumber: number;
25
- referenceSequenceNumber: number;
26
- content: any;
27
- localOpMetadata: unknown;
28
- opMetadata: Record<string, unknown> | undefined;
29
- }
30
-
31
18
  /**
32
19
  * This represents a message that has been submitted and is added to the pending queue when `submit` is called on the
33
20
  * ContainerRuntime. This message has either not been ack'd by the server or has not been submitted to the server yet.
34
21
  */
35
- export interface IPendingMessageNew {
22
+ export interface IPendingMessage {
36
23
  type: "message";
37
24
  clientSequenceNumber: number;
38
25
  referenceSequenceNumber: number;
@@ -41,16 +28,11 @@ export interface IPendingMessageNew {
41
28
  opMetadata: Record<string, unknown> | undefined;
42
29
  }
43
30
 
44
- /**
45
- * ! TODO: Remove this type in "2.0.0-internal.7.0.0" (AB#4763)
46
- */
47
- export type IPendingState = IPendingMessageOld | IPendingMessageNew;
48
-
49
31
  export interface IPendingLocalState {
50
32
  /**
51
33
  * list of pending states, including ops and batch information
52
34
  */
53
- pendingStates: IPendingState[];
35
+ pendingStates: IPendingMessage[];
54
36
  }
55
37
 
56
38
  export interface IPendingBatchMessage {
@@ -99,13 +81,13 @@ function buildPendingMessageContent(
99
81
  * It verifies that all the ops are acked, are received in the right order and batch information is correct.
100
82
  */
101
83
  export class PendingStateManager implements IDisposable {
102
- private readonly pendingMessages = new Deque<IPendingMessageNew>();
103
- private readonly initialMessages = new Deque<IPendingMessageNew>();
84
+ private readonly pendingMessages = new Deque<IPendingMessage>();
85
+ private readonly initialMessages = new Deque<IPendingMessage>();
104
86
 
105
87
  /**
106
88
  * Sequenced local ops that are saved when stashing since pending ops may depend on them
107
89
  */
108
- private savedOps: IPendingMessageNew[] = [];
90
+ private savedOps: IPendingMessage[] = [];
109
91
 
110
92
  private readonly disposeOnce = new Lazy<void>(() => {
111
93
  this.initialMessages.clear();
@@ -169,29 +151,8 @@ export class PendingStateManager implements IDisposable {
169
151
  initialLocalState: IPendingLocalState | undefined,
170
152
  private readonly logger: ITelemetryLoggerExt | undefined,
171
153
  ) {
172
- /**
173
- * Convert old local state format to the new format (IPendingMessageOld to IPendingMessageNew)
174
- * ! TODO: Remove this conversion in "2.0.0-internal.7.0.0" (AB#4763)
175
- */
176
154
  if (initialLocalState?.pendingStates) {
177
- for (const initialState of initialLocalState.pendingStates) {
178
- let messageContent = initialState.content;
179
- if (
180
- (initialState as IPendingMessageOld).messageType !== undefined &&
181
- typeof initialState.content !== "string"
182
- ) {
183
- // Convert IPendingMessageOld to IPendingMessageNew
184
- messageContent = JSON.stringify({
185
- type: (initialState as IPendingMessageOld).messageType,
186
- contents: initialState.content,
187
- });
188
- }
189
- // Note: this object may contain "messageType" prop, but it should not be easily accesible due to interface being used
190
- this.initialMessages.push({
191
- ...initialState,
192
- content: messageContent,
193
- });
194
- }
155
+ this.initialMessages.push(...initialLocalState.pendingStates);
195
156
  }
196
157
  }
197
158
 
@@ -213,7 +174,7 @@ export class PendingStateManager implements IDisposable {
213
174
  localOpMetadata: unknown,
214
175
  opMetadata: Record<string, unknown> | undefined,
215
176
  ) {
216
- const pendingMessage: IPendingMessageNew = {
177
+ const pendingMessage: IPendingMessage = {
217
178
  type: "message",
218
179
  clientSequenceNumber: -1, // dummy value (not to be used anywhere)
219
180
  referenceSequenceNumber,
@@ -357,6 +318,7 @@ export class PendingStateManager implements IDisposable {
357
318
  {
358
319
  runtimeVersion: pkgVersion,
359
320
  batchClientId:
321
+ // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
360
322
  this.pendingBatchBeginMessage.clientId === null
361
323
  ? "null"
362
324
  : this.pendingBatchBeginMessage.clientId,
@@ -271,6 +271,7 @@ class ScheduleManagerCore {
271
271
  {
272
272
  runtimeVersion: pkgVersion,
273
273
  batchClientId:
274
+ // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
274
275
  this.currentBatchClientId === null ? "null" : this.currentBatchClientId,
275
276
  pauseSequenceNumber: this.pauseSequenceNumber,
276
277
  localBatch: this.currentBatchClientId === this.getClientId(),
@@ -306,6 +307,7 @@ class ScheduleManagerCore {
306
307
  throw new DataCorruptionError("OpBatchIncomplete", {
307
308
  runtimeVersion: pkgVersion,
308
309
  batchClientId:
310
+ // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
309
311
  this.currentBatchClientId === null ? "null" : this.currentBatchClientId,
310
312
  pauseSequenceNumber: this.pauseSequenceNumber,
311
313
  localBatch: this.currentBatchClientId === this.getClientId(),
@@ -15,8 +15,8 @@ import {
15
15
  } from "@fluidframework/telemetry-utils";
16
16
  import { ILoader, LoaderHeader } from "@fluidframework/container-definitions";
17
17
  import { DriverHeader } from "@fluidframework/driver-definitions";
18
- import { requestFluidObject } from "@fluidframework/runtime-utils";
19
18
  import { FluidObject, IFluidHandleContext, IRequest } from "@fluidframework/core-interfaces";
19
+ import { responseToException } from "@fluidframework/runtime-utils";
20
20
  import { ISummaryConfiguration } from "../containerRuntime";
21
21
  import { ICancellableSummarizerController } from "./runWhileConnectedCoordinator";
22
22
  import { summarizerClientType } from "./summarizerClientElection";
@@ -49,7 +49,10 @@ export class SummarizingWarning
49
49
  readonly errorType = summarizingError;
50
50
  readonly canRetry = true;
51
51
 
52
- constructor(errorMessage: string, readonly logged: boolean = false) {
52
+ constructor(
53
+ errorMessage: string,
54
+ readonly logged: boolean = false,
55
+ ) {
53
56
  super(errorMessage);
54
57
  }
55
58
 
@@ -107,6 +110,7 @@ export class Summarizer extends TypedEventEmitter<ISummarizerEvents> implements
107
110
  * interface will expect an absolute URL and will not handle "/".
108
111
  * @param loader - the loader that resolves the request
109
112
  * @param url - the URL used to resolve the container
113
+ * @deprecated Creating a summarizer is not a publicly supported API. Please remove all usage of this static method.
110
114
  */
111
115
  public static async create(loader: ILoader, url: string): Promise<ISummarizer> {
112
116
  const request: IRequest = {
@@ -123,11 +127,20 @@ export class Summarizer extends TypedEventEmitter<ISummarizerEvents> implements
123
127
  };
124
128
 
125
129
  const resolvedContainer = await loader.resolve(request);
126
- const fluidObject: FluidObject<ISummarizer> | undefined = resolvedContainer.getEntryPoint
127
- ? await resolvedContainer.getEntryPoint?.()
128
- : await requestFluidObject<FluidObject<ISummarizer>>(resolvedContainer, {
129
- url: "_summarizer",
130
- });
130
+ let fluidObject: FluidObject<ISummarizer> | undefined;
131
+
132
+ // Older containers may not have the "getEntryPoint" API
133
+ // ! This check will need to stay until LTS of loader moves past 2.0.0-internal.7.0.0
134
+ if (resolvedContainer.getEntryPoint !== undefined) {
135
+ fluidObject = await resolvedContainer.getEntryPoint();
136
+ } else {
137
+ const response = await resolvedContainer.request({ url: "_summarizer" });
138
+ if (response.status !== 200 || response.mimeType !== "fluid/object") {
139
+ throw responseToException(response, request);
140
+ }
141
+ fluidObject = response.value;
142
+ }
143
+
131
144
  if (fluidObject?.ISummarizer === undefined) {
132
145
  throw new UsageError("Fluid object does not implement ISummarizer");
133
146
  }
@@ -405,6 +405,7 @@ export class SummaryCollection extends TypedEventEmitter<ISummaryCollectionOpEve
405
405
  private handleSummaryAck(op: ISummaryAckMessage) {
406
406
  const seq = op.contents.summaryProposal.summarySequenceNumber;
407
407
  const summary = this.pendingSummaries.get(seq);
408
+ // eslint-disable-next-line @typescript-eslint/prefer-optional-chain -- optional chain is not logically equivalent
408
409
  if (!summary || summary.summaryOp === undefined) {
409
410
  // Summary ack without an op should be rare. We could fetch the
410
411
  // reference sequence number from the snapshot, but instead we
@@ -47,12 +47,12 @@ export async function raceTimer<T>(
47
47
  cancellationToken?: ISummaryCancellationToken,
48
48
  ): Promise<raceTimerResult<T>> {
49
49
  const promises: Promise<raceTimerResult<T>>[] = [
50
- promise.then((value) => ({ result: "done", value } as const)),
51
- timer.then(({ timerResult: result }) => ({ result } as const)),
50
+ promise.then((value) => ({ result: "done", value }) as const),
51
+ timer.then(({ timerResult: result }) => ({ result }) as const),
52
52
  ];
53
53
  if (cancellationToken !== undefined) {
54
54
  promises.push(
55
- cancellationToken.waitCancelled.then(() => ({ result: "cancelled" } as const)),
55
+ cancellationToken.waitCancelled.then(() => ({ result: "cancelled" }) as const),
56
56
  );
57
57
  }
58
58
  return Promise.race(promises);
@@ -114,7 +114,7 @@ export class SummaryManager extends TypedEventEmitter<ISummarizerEvents> impleme
114
114
  parentLogger: ITelemetryBaseLogger,
115
115
  /** Creates summarizer by asking interactive container to spawn summarizing container and
116
116
  * get back its Summarizer instance. */
117
- private readonly requestSummarizerFn: () => Promise<ISummarizer>,
117
+ private readonly createSummarizerFn: () => Promise<ISummarizer>,
118
118
  private readonly startThrottler: IThrottler,
119
119
  {
120
120
  initialDelayMs = defaultInitialDelayMs,
@@ -264,7 +264,7 @@ export class SummaryManager extends TypedEventEmitter<ISummarizerEvents> impleme
264
264
  );
265
265
  this.state = SummaryManagerState.Running;
266
266
 
267
- const summarizer = await this.requestSummarizerFn();
267
+ const summarizer = await this.createSummarizerFn();
268
268
  this.summarizer = summarizer;
269
269
  this.summarizer.on("summarize", this.handleSummarizeEvent);
270
270