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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (335) hide show
  1. package/CHANGELOG.md +119 -0
  2. package/api-extractor.json +1 -1
  3. package/api-report/container-runtime.api.md +864 -0
  4. package/dist/blobManager.d.ts +4 -4
  5. package/dist/blobManager.d.ts.map +1 -1
  6. package/dist/blobManager.js +55 -71
  7. package/dist/blobManager.js.map +1 -1
  8. package/dist/connectionTelemetry.d.ts.map +1 -1
  9. package/dist/connectionTelemetry.js +75 -42
  10. package/dist/connectionTelemetry.js.map +1 -1
  11. package/dist/container-runtime-alpha.d.ts +1742 -0
  12. package/dist/container-runtime-beta.d.ts +1742 -0
  13. package/dist/container-runtime-public.d.ts +1742 -0
  14. package/dist/container-runtime-untrimmed.d.ts +1803 -0
  15. package/dist/containerHandleContext.js +3 -3
  16. package/dist/containerHandleContext.js.map +1 -1
  17. package/dist/containerRuntime.d.ts +88 -98
  18. package/dist/containerRuntime.d.ts.map +1 -1
  19. package/dist/containerRuntime.js +466 -453
  20. package/dist/containerRuntime.js.map +1 -1
  21. package/dist/dataStore.js +11 -11
  22. package/dist/dataStore.js.map +1 -1
  23. package/dist/dataStoreContext.d.ts +2 -4
  24. package/dist/dataStoreContext.d.ts.map +1 -1
  25. package/dist/dataStoreContext.js +60 -59
  26. package/dist/dataStoreContext.js.map +1 -1
  27. package/dist/dataStoreRegistry.d.ts +3 -0
  28. package/dist/dataStoreRegistry.d.ts.map +1 -1
  29. package/dist/dataStoreRegistry.js +6 -3
  30. package/dist/dataStoreRegistry.js.map +1 -1
  31. package/dist/dataStores.js +1 -1
  32. package/dist/dataStores.js.map +1 -1
  33. package/dist/deltaManagerProxyBase.js +4 -4
  34. package/dist/deltaManagerProxyBase.js.map +1 -1
  35. package/dist/deltaManagerSummarizerProxy.js +6 -6
  36. package/dist/deltaManagerSummarizerProxy.js.map +1 -1
  37. package/dist/deltaScheduler.js.map +1 -1
  38. package/dist/error.d.ts.map +1 -1
  39. package/dist/error.js.map +1 -1
  40. package/dist/gc/garbageCollection.d.ts.map +1 -1
  41. package/dist/gc/garbageCollection.js +23 -24
  42. package/dist/gc/garbageCollection.js.map +1 -1
  43. package/dist/gc/gcConfigs.js +1 -1
  44. package/dist/gc/gcConfigs.js.map +1 -1
  45. package/dist/gc/gcDefinitions.d.ts +34 -24
  46. package/dist/gc/gcDefinitions.d.ts.map +1 -1
  47. package/dist/gc/gcDefinitions.js +10 -7
  48. package/dist/gc/gcDefinitions.js.map +1 -1
  49. package/dist/gc/gcSummaryDefinitions.d.ts +1 -1
  50. package/dist/gc/gcSummaryDefinitions.js.map +1 -1
  51. package/dist/gc/gcTelemetry.d.ts +2 -2
  52. package/dist/gc/gcTelemetry.d.ts.map +1 -1
  53. package/dist/gc/gcTelemetry.js +5 -5
  54. package/dist/gc/gcTelemetry.js.map +1 -1
  55. package/dist/gc/gcUnreferencedStateTracker.js +3 -3
  56. package/dist/gc/gcUnreferencedStateTracker.js.map +1 -1
  57. package/dist/gc/index.d.ts +1 -1
  58. package/dist/gc/index.d.ts.map +1 -1
  59. package/dist/gc/index.js +3 -3
  60. package/dist/gc/index.js.map +1 -1
  61. package/dist/id-compressor/appendOnlySortedMap.js.map +1 -1
  62. package/dist/id-compressor/idCompressor.js.map +1 -1
  63. package/dist/id-compressor/identifiers.d.ts +3 -3
  64. package/dist/id-compressor/identifiers.d.ts.map +1 -1
  65. package/dist/id-compressor/utilities.d.ts +3 -0
  66. package/dist/id-compressor/utilities.d.ts.map +1 -1
  67. package/dist/id-compressor/utilities.js +3 -0
  68. package/dist/id-compressor/utilities.js.map +1 -1
  69. package/dist/index.d.ts +5 -3
  70. package/dist/index.d.ts.map +1 -1
  71. package/dist/index.js +6 -2
  72. package/dist/index.js.map +1 -1
  73. package/dist/messageTypes.d.ts +137 -0
  74. package/dist/messageTypes.d.ts.map +1 -0
  75. package/dist/messageTypes.js +32 -0
  76. package/dist/messageTypes.js.map +1 -0
  77. package/dist/opLifecycle/batchManager.js +6 -6
  78. package/dist/opLifecycle/batchManager.js.map +1 -1
  79. package/dist/opLifecycle/definitions.d.ts +7 -3
  80. package/dist/opLifecycle/definitions.d.ts.map +1 -1
  81. package/dist/opLifecycle/definitions.js.map +1 -1
  82. package/dist/opLifecycle/opDecompressor.d.ts.map +1 -1
  83. package/dist/opLifecycle/opDecompressor.js +0 -4
  84. package/dist/opLifecycle/opDecompressor.js.map +1 -1
  85. package/dist/opLifecycle/opGroupingManager.d.ts.map +1 -1
  86. package/dist/opLifecycle/opGroupingManager.js.map +1 -1
  87. package/dist/opLifecycle/opSplitter.js +3 -3
  88. package/dist/opLifecycle/opSplitter.js.map +1 -1
  89. package/dist/opLifecycle/outbox.d.ts.map +1 -1
  90. package/dist/opLifecycle/outbox.js +7 -2
  91. package/dist/opLifecycle/outbox.js.map +1 -1
  92. package/dist/opLifecycle/remoteMessageProcessor.d.ts +17 -3
  93. package/dist/opLifecycle/remoteMessageProcessor.d.ts.map +1 -1
  94. package/dist/opLifecycle/remoteMessageProcessor.js +38 -25
  95. package/dist/opLifecycle/remoteMessageProcessor.js.map +1 -1
  96. package/dist/packageVersion.d.ts +1 -1
  97. package/dist/packageVersion.js +1 -1
  98. package/dist/packageVersion.js.map +1 -1
  99. package/dist/pendingStateManager.d.ts +4 -20
  100. package/dist/pendingStateManager.d.ts.map +1 -1
  101. package/dist/pendingStateManager.js +36 -46
  102. package/dist/pendingStateManager.js.map +1 -1
  103. package/dist/scheduleManager.js +6 -2
  104. package/dist/scheduleManager.js.map +1 -1
  105. package/dist/summary/orderedClientElection.d.ts +7 -4
  106. package/dist/summary/orderedClientElection.d.ts.map +1 -1
  107. package/dist/summary/orderedClientElection.js +54 -54
  108. package/dist/summary/orderedClientElection.js.map +1 -1
  109. package/dist/summary/runWhileConnectedCoordinator.d.ts +5 -0
  110. package/dist/summary/runWhileConnectedCoordinator.d.ts.map +1 -1
  111. package/dist/summary/runWhileConnectedCoordinator.js +7 -6
  112. package/dist/summary/runWhileConnectedCoordinator.js.map +1 -1
  113. package/dist/summary/runningSummarizer.d.ts.map +1 -1
  114. package/dist/summary/runningSummarizer.js +40 -38
  115. package/dist/summary/runningSummarizer.js.map +1 -1
  116. package/dist/summary/summarizer.d.ts +2 -0
  117. package/dist/summary/summarizer.d.ts.map +1 -1
  118. package/dist/summary/summarizer.js +18 -8
  119. package/dist/summary/summarizer.js.map +1 -1
  120. package/dist/summary/summarizerClientElection.js +6 -6
  121. package/dist/summary/summarizerClientElection.js.map +1 -1
  122. package/dist/summary/summarizerHeuristics.js +9 -9
  123. package/dist/summary/summarizerHeuristics.js.map +1 -1
  124. package/dist/summary/summarizerNode/summarizerNode.d.ts +1 -1
  125. package/dist/summary/summarizerNode/summarizerNode.js +8 -8
  126. package/dist/summary/summarizerNode/summarizerNode.js.map +1 -1
  127. package/dist/summary/summarizerNode/summarizerNodeUtils.d.ts +1 -1
  128. package/dist/summary/summarizerNode/summarizerNodeUtils.d.ts.map +1 -1
  129. package/dist/summary/summarizerNode/summarizerNodeUtils.js +3 -3
  130. package/dist/summary/summarizerNode/summarizerNodeUtils.js.map +1 -1
  131. package/dist/summary/summarizerNode/summarizerNodeWithGc.d.ts +2 -2
  132. package/dist/summary/summarizerNode/summarizerNodeWithGc.d.ts.map +1 -1
  133. package/dist/summary/summarizerTypes.d.ts +107 -22
  134. package/dist/summary/summarizerTypes.d.ts.map +1 -1
  135. package/dist/summary/summarizerTypes.js.map +1 -1
  136. package/dist/summary/summaryCollection.d.ts +18 -2
  137. package/dist/summary/summaryCollection.d.ts.map +1 -1
  138. package/dist/summary/summaryCollection.js +23 -21
  139. package/dist/summary/summaryCollection.js.map +1 -1
  140. package/dist/summary/summaryFormat.d.ts +15 -6
  141. package/dist/summary/summaryFormat.d.ts.map +1 -1
  142. package/dist/summary/summaryFormat.js.map +1 -1
  143. package/dist/summary/summaryGenerator.d.ts +3 -3
  144. package/dist/summary/summaryGenerator.d.ts.map +1 -1
  145. package/dist/summary/summaryGenerator.js.map +1 -1
  146. package/dist/summary/summaryManager.d.ts +2 -2
  147. package/dist/summary/summaryManager.d.ts.map +1 -1
  148. package/dist/summary/summaryManager.js +10 -10
  149. package/dist/summary/summaryManager.js.map +1 -1
  150. package/dist/throttler.js +16 -16
  151. package/dist/throttler.js.map +1 -1
  152. package/dist/tsdoc-metadata.json +1 -1
  153. package/lib/blobManager.d.ts +4 -4
  154. package/lib/blobManager.d.ts.map +1 -1
  155. package/lib/blobManager.js +56 -72
  156. package/lib/blobManager.js.map +1 -1
  157. package/lib/connectionTelemetry.d.ts.map +1 -1
  158. package/lib/connectionTelemetry.js +76 -43
  159. package/lib/connectionTelemetry.js.map +1 -1
  160. package/lib/containerHandleContext.js +3 -3
  161. package/lib/containerHandleContext.js.map +1 -1
  162. package/lib/containerRuntime.d.ts +88 -98
  163. package/lib/containerRuntime.d.ts.map +1 -1
  164. package/lib/containerRuntime.js +424 -416
  165. package/lib/containerRuntime.js.map +1 -1
  166. package/lib/dataStore.js +11 -11
  167. package/lib/dataStore.js.map +1 -1
  168. package/lib/dataStoreContext.d.ts +2 -4
  169. package/lib/dataStoreContext.d.ts.map +1 -1
  170. package/lib/dataStoreContext.js +60 -59
  171. package/lib/dataStoreContext.js.map +1 -1
  172. package/lib/dataStoreRegistry.d.ts +3 -0
  173. package/lib/dataStoreRegistry.d.ts.map +1 -1
  174. package/lib/dataStoreRegistry.js +6 -3
  175. package/lib/dataStoreRegistry.js.map +1 -1
  176. package/lib/dataStores.js +1 -1
  177. package/lib/dataStores.js.map +1 -1
  178. package/lib/deltaManagerProxyBase.js +4 -4
  179. package/lib/deltaManagerProxyBase.js.map +1 -1
  180. package/lib/deltaManagerSummarizerProxy.js +6 -6
  181. package/lib/deltaManagerSummarizerProxy.js.map +1 -1
  182. package/lib/deltaScheduler.js.map +1 -1
  183. package/lib/error.d.ts.map +1 -1
  184. package/lib/error.js.map +1 -1
  185. package/lib/gc/garbageCollection.d.ts.map +1 -1
  186. package/lib/gc/garbageCollection.js +23 -24
  187. package/lib/gc/garbageCollection.js.map +1 -1
  188. package/lib/gc/gcConfigs.js +2 -2
  189. package/lib/gc/gcConfigs.js.map +1 -1
  190. package/lib/gc/gcDefinitions.d.ts +34 -24
  191. package/lib/gc/gcDefinitions.d.ts.map +1 -1
  192. package/lib/gc/gcDefinitions.js +9 -6
  193. package/lib/gc/gcDefinitions.js.map +1 -1
  194. package/lib/gc/gcSummaryDefinitions.d.ts +1 -1
  195. package/lib/gc/gcSummaryDefinitions.js.map +1 -1
  196. package/lib/gc/gcTelemetry.d.ts +2 -2
  197. package/lib/gc/gcTelemetry.d.ts.map +1 -1
  198. package/lib/gc/gcTelemetry.js +5 -5
  199. package/lib/gc/gcTelemetry.js.map +1 -1
  200. package/lib/gc/gcUnreferencedStateTracker.js +3 -3
  201. package/lib/gc/gcUnreferencedStateTracker.js.map +1 -1
  202. package/lib/gc/index.d.ts +1 -1
  203. package/lib/gc/index.d.ts.map +1 -1
  204. package/lib/gc/index.js +1 -1
  205. package/lib/gc/index.js.map +1 -1
  206. package/lib/id-compressor/appendOnlySortedMap.js.map +1 -1
  207. package/lib/id-compressor/idCompressor.js.map +1 -1
  208. package/lib/id-compressor/identifiers.d.ts +3 -3
  209. package/lib/id-compressor/identifiers.d.ts.map +1 -1
  210. package/lib/id-compressor/utilities.d.ts +3 -0
  211. package/lib/id-compressor/utilities.d.ts.map +1 -1
  212. package/lib/id-compressor/utilities.js +3 -0
  213. package/lib/id-compressor/utilities.js.map +1 -1
  214. package/lib/index.d.ts +5 -3
  215. package/lib/index.d.ts.map +1 -1
  216. package/lib/index.js +3 -1
  217. package/lib/index.js.map +1 -1
  218. package/lib/messageTypes.d.ts +137 -0
  219. package/lib/messageTypes.d.ts.map +1 -0
  220. package/lib/messageTypes.js +29 -0
  221. package/lib/messageTypes.js.map +1 -0
  222. package/lib/opLifecycle/batchManager.js +6 -6
  223. package/lib/opLifecycle/batchManager.js.map +1 -1
  224. package/lib/opLifecycle/definitions.d.ts +7 -3
  225. package/lib/opLifecycle/definitions.d.ts.map +1 -1
  226. package/lib/opLifecycle/definitions.js.map +1 -1
  227. package/lib/opLifecycle/opDecompressor.d.ts.map +1 -1
  228. package/lib/opLifecycle/opDecompressor.js +0 -4
  229. package/lib/opLifecycle/opDecompressor.js.map +1 -1
  230. package/lib/opLifecycle/opGroupingManager.d.ts.map +1 -1
  231. package/lib/opLifecycle/opGroupingManager.js.map +1 -1
  232. package/lib/opLifecycle/opSplitter.js +1 -1
  233. package/lib/opLifecycle/opSplitter.js.map +1 -1
  234. package/lib/opLifecycle/outbox.d.ts.map +1 -1
  235. package/lib/opLifecycle/outbox.js +7 -2
  236. package/lib/opLifecycle/outbox.js.map +1 -1
  237. package/lib/opLifecycle/remoteMessageProcessor.d.ts +17 -3
  238. package/lib/opLifecycle/remoteMessageProcessor.d.ts.map +1 -1
  239. package/lib/opLifecycle/remoteMessageProcessor.js +37 -24
  240. package/lib/opLifecycle/remoteMessageProcessor.js.map +1 -1
  241. package/lib/packageVersion.d.ts +1 -1
  242. package/lib/packageVersion.js +1 -1
  243. package/lib/packageVersion.js.map +1 -1
  244. package/lib/pendingStateManager.d.ts +4 -20
  245. package/lib/pendingStateManager.d.ts.map +1 -1
  246. package/lib/pendingStateManager.js +35 -45
  247. package/lib/pendingStateManager.js.map +1 -1
  248. package/lib/scheduleManager.js +6 -2
  249. package/lib/scheduleManager.js.map +1 -1
  250. package/lib/summary/orderedClientElection.d.ts +7 -4
  251. package/lib/summary/orderedClientElection.d.ts.map +1 -1
  252. package/lib/summary/orderedClientElection.js +54 -54
  253. package/lib/summary/orderedClientElection.js.map +1 -1
  254. package/lib/summary/runWhileConnectedCoordinator.d.ts +5 -0
  255. package/lib/summary/runWhileConnectedCoordinator.d.ts.map +1 -1
  256. package/lib/summary/runWhileConnectedCoordinator.js +7 -6
  257. package/lib/summary/runWhileConnectedCoordinator.js.map +1 -1
  258. package/lib/summary/runningSummarizer.d.ts.map +1 -1
  259. package/lib/summary/runningSummarizer.js +40 -38
  260. package/lib/summary/runningSummarizer.js.map +1 -1
  261. package/lib/summary/summarizer.d.ts +2 -0
  262. package/lib/summary/summarizer.d.ts.map +1 -1
  263. package/lib/summary/summarizer.js +19 -9
  264. package/lib/summary/summarizer.js.map +1 -1
  265. package/lib/summary/summarizerClientElection.js +6 -6
  266. package/lib/summary/summarizerClientElection.js.map +1 -1
  267. package/lib/summary/summarizerHeuristics.js +9 -9
  268. package/lib/summary/summarizerHeuristics.js.map +1 -1
  269. package/lib/summary/summarizerNode/summarizerNode.d.ts +1 -1
  270. package/lib/summary/summarizerNode/summarizerNode.js +8 -8
  271. package/lib/summary/summarizerNode/summarizerNode.js.map +1 -1
  272. package/lib/summary/summarizerNode/summarizerNodeUtils.d.ts +1 -1
  273. package/lib/summary/summarizerNode/summarizerNodeUtils.d.ts.map +1 -1
  274. package/lib/summary/summarizerNode/summarizerNodeUtils.js +3 -3
  275. package/lib/summary/summarizerNode/summarizerNodeUtils.js.map +1 -1
  276. package/lib/summary/summarizerNode/summarizerNodeWithGc.d.ts +2 -2
  277. package/lib/summary/summarizerNode/summarizerNodeWithGc.d.ts.map +1 -1
  278. package/lib/summary/summarizerTypes.d.ts +107 -22
  279. package/lib/summary/summarizerTypes.d.ts.map +1 -1
  280. package/lib/summary/summarizerTypes.js.map +1 -1
  281. package/lib/summary/summaryCollection.d.ts +18 -2
  282. package/lib/summary/summaryCollection.d.ts.map +1 -1
  283. package/lib/summary/summaryCollection.js +23 -21
  284. package/lib/summary/summaryCollection.js.map +1 -1
  285. package/lib/summary/summaryFormat.d.ts +15 -6
  286. package/lib/summary/summaryFormat.d.ts.map +1 -1
  287. package/lib/summary/summaryFormat.js.map +1 -1
  288. package/lib/summary/summaryGenerator.d.ts +3 -3
  289. package/lib/summary/summaryGenerator.d.ts.map +1 -1
  290. package/lib/summary/summaryGenerator.js.map +1 -1
  291. package/lib/summary/summaryManager.d.ts +2 -2
  292. package/lib/summary/summaryManager.d.ts.map +1 -1
  293. package/lib/summary/summaryManager.js +9 -9
  294. package/lib/summary/summaryManager.js.map +1 -1
  295. package/lib/throttler.js +16 -16
  296. package/lib/throttler.js.map +1 -1
  297. package/package.json +27 -28
  298. package/src/blobManager.ts +64 -77
  299. package/src/connectionTelemetry.ts +97 -52
  300. package/src/containerRuntime.ts +337 -341
  301. package/src/dataStore.ts +3 -3
  302. package/src/dataStoreContext.ts +7 -7
  303. package/src/dataStoreRegistry.ts +3 -0
  304. package/src/dataStores.ts +1 -1
  305. package/src/error.ts +4 -1
  306. package/src/gc/garbageCollection.ts +12 -11
  307. package/src/gc/gcConfigs.ts +3 -3
  308. package/src/gc/gcDefinitions.ts +35 -25
  309. package/src/gc/gcSummaryDefinitions.ts +1 -1
  310. package/src/gc/gcTelemetry.ts +6 -5
  311. package/src/gc/index.ts +2 -2
  312. package/src/id-compressor/utilities.ts +3 -0
  313. package/src/index.ts +21 -5
  314. package/src/messageTypes.ts +228 -0
  315. package/src/opLifecycle/README.md +93 -68
  316. package/src/opLifecycle/definitions.ts +5 -1
  317. package/src/opLifecycle/opDecompressor.ts +0 -8
  318. package/src/opLifecycle/opGroupingManager.ts +2 -4
  319. package/src/opLifecycle/opSplitter.ts +2 -2
  320. package/src/opLifecycle/outbox.ts +3 -0
  321. package/src/opLifecycle/remoteMessageProcessor.ts +54 -33
  322. package/src/packageVersion.ts +1 -1
  323. package/src/pendingStateManager.ts +31 -52
  324. package/src/scheduleManager.ts +2 -0
  325. package/src/summary/orderedClientElection.ts +4 -1
  326. package/src/summary/runWhileConnectedCoordinator.ts +5 -1
  327. package/src/summary/runningSummarizer.ts +3 -1
  328. package/src/summary/summarizer.ts +21 -7
  329. package/src/summary/summarizerNode/summarizerNode.ts +1 -1
  330. package/src/summary/summarizerTypes.ts +96 -11
  331. package/src/summary/summaryCollection.ts +19 -1
  332. package/src/summary/summaryFormat.ts +11 -1
  333. package/src/summary/summaryGenerator.ts +3 -3
  334. package/src/summary/summaryManager.ts +2 -2
  335. package/src/gc/gcEarlyAdoption.md +0 -145
@@ -18,22 +18,28 @@ var SummaryManagerState;
18
18
  SummaryManagerState[SummaryManagerState["Starting"] = 1] = "Starting";
19
19
  SummaryManagerState[SummaryManagerState["Running"] = 2] = "Running";
20
20
  SummaryManagerState[SummaryManagerState["Stopping"] = 3] = "Stopping";
21
- })(SummaryManagerState = exports.SummaryManagerState || (exports.SummaryManagerState = {}));
21
+ })(SummaryManagerState || (exports.SummaryManagerState = SummaryManagerState = {}));
22
22
  /**
23
23
  * SummaryManager is created by parent container (i.e. interactive container with clientType !== "summarizer") only.
24
24
  * It observes changes in calculated summarizer and reacts to changes by either creating summarizer client or
25
25
  * stopping existing summarizer client.
26
26
  */
27
27
  class SummaryManager extends client_utils_1.TypedEventEmitter {
28
+ get disposed() {
29
+ return this._disposed;
30
+ }
31
+ get currentState() {
32
+ return this.state;
33
+ }
28
34
  constructor(clientElection, connectedState, summaryCollection, parentLogger,
29
35
  /** Creates summarizer by asking interactive container to spawn summarizing container and
30
36
  * get back its Summarizer instance. */
31
- requestSummarizerFn, startThrottler, { initialDelayMs = defaultInitialDelayMs, opsToBypassInitialDelay = defaultOpsToBypassInitialDelay, } = {}, disableHeuristics) {
37
+ createSummarizerFn, startThrottler, { initialDelayMs = defaultInitialDelayMs, opsToBypassInitialDelay = defaultOpsToBypassInitialDelay, } = {}, disableHeuristics) {
32
38
  super();
33
39
  this.clientElection = clientElection;
34
40
  this.connectedState = connectedState;
35
41
  this.summaryCollection = summaryCollection;
36
- this.requestSummarizerFn = requestSummarizerFn;
42
+ this.createSummarizerFn = createSummarizerFn;
37
43
  this.startThrottler = startThrottler;
38
44
  this.disableHeuristics = disableHeuristics;
39
45
  this.state = SummaryManagerState.Off;
@@ -96,12 +102,6 @@ class SummaryManager extends client_utils_1.TypedEventEmitter {
96
102
  this.opsToBypassInitialDelay = opsToBypassInitialDelay;
97
103
  this.initialDelayMs = initialDelayMs;
98
104
  }
99
- get disposed() {
100
- return this._disposed;
101
- }
102
- get currentState() {
103
- return this.state;
104
- }
105
105
  /**
106
106
  * Until start is called, the SummaryManager won't begin attempting to start summarization. This ensures there's
107
107
  * a window between construction and starting where the caller can attach listeners.
@@ -158,7 +158,7 @@ class SummaryManager extends client_utils_1.TypedEventEmitter {
158
158
  // state === Starting || state === Running.
159
159
  (0, core_utils_1.assert)(this.state === SummaryManagerState.Starting, 0x263 /* "Expected: starting" */);
160
160
  this.state = SummaryManagerState.Running;
161
- const summarizer = await this.requestSummarizerFn();
161
+ const summarizer = await this.createSummarizerFn();
162
162
  this.summarizer = summarizer;
163
163
  this.summarizer.on("summarize", this.handleSummarizeEvent);
164
164
  // Re-validate that it need to be running. Due to asynchrony, it may be not the case anymore
@@ -1 +1 @@
1
- {"version":3,"file":"summaryManager.js","sourceRoot":"","sources":["../../src/summary/summaryManager.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport {\n\tIDisposable,\n\tIEvent,\n\tIEventProvider,\n\tITelemetryBaseLogger,\n} from \"@fluidframework/core-interfaces\";\nimport { assert } from \"@fluidframework/core-utils\";\nimport { TypedEventEmitter } from \"@fluid-internal/client-utils\";\nimport {\n\tcreateChildLogger,\n\tITelemetryLoggerExt,\n\tPerformanceEvent,\n} from \"@fluidframework/telemetry-utils\";\nimport { DriverErrorTypes } from \"@fluidframework/driver-definitions\";\nimport { IThrottler } from \"../throttler\";\nimport { ISummarizerClientElection } from \"./summarizerClientElection\";\nimport {\n\tEnqueueSummarizeResult,\n\tIEnqueueSummarizeOptions,\n\tIOnDemandSummarizeOptions,\n\tISummarizeEventProps,\n\tISummarizeResults,\n\tISummarizer,\n\tISummarizerEvents,\n\tSummarizerStopReason,\n} from \"./summarizerTypes\";\nimport { SummaryCollection } from \"./summaryCollection\";\nimport { Summarizer } from \"./summarizer\";\n\nconst defaultInitialDelayMs = 5000;\nconst defaultOpsToBypassInitialDelay = 4000;\n\nexport enum SummaryManagerState {\n\tOff = 0,\n\tStarting = 1,\n\tRunning = 2,\n\tStopping = 3,\n}\n\n// Please note that all reasons in this list are not errors,\n// and thus they are not raised today to parent container as error.\n// If this needs to be changed in future, we should re-evaluate what and how we raise to summarizer\ntype StopReason = Extract<\n\tSummarizerStopReason,\n\t\"parentNotConnected\" | \"notElectedParent\" | \"notElectedClient\"\n>;\ntype ShouldSummarizeState =\n\t| { shouldSummarize: true }\n\t| { shouldSummarize: false; stopReason: StopReason };\n\nexport interface IConnectedEvents extends IEvent {\n\t(event: \"connected\", listener: (clientId: string) => void);\n\t(event: \"disconnected\", listener: () => void);\n}\n\n/**\n * IConnectedState describes an object that SummaryManager can watch to observe connection/disconnection.\n *\n * Under current implementation, its role will be fulfilled by the ContainerRuntime, but this could be replaced\n * with anything else that fulfills the contract if we want to shift the layer that the SummaryManager lives at.\n */\nexport interface IConnectedState extends IEventProvider<IConnectedEvents> {\n\treadonly connected: boolean;\n\n\t/**\n\t * Under current implementation this is undefined if we've never connected, otherwise it's the clientId from our\n\t * latest connection (even if we've since disconnected!). Although this happens to be the behavior we want in\n\t * SummaryManager, I suspect that globally we may eventually want to modify this behavior (e.g. make clientId\n\t * undefined while disconnected). To protect against this, let's assume this field can't be trusted while\n\t * disconnected and instead separately track \"latest clientId\" in SummaryManager.\n\t */\n\treadonly clientId: string | undefined;\n}\n\nexport interface ISummaryManagerConfig {\n\tinitialDelayMs: number;\n\topsToBypassInitialDelay: number;\n}\n\n/**\n * SummaryManager is created by parent container (i.e. interactive container with clientType !== \"summarizer\") only.\n * It observes changes in calculated summarizer and reacts to changes by either creating summarizer client or\n * stopping existing summarizer client.\n */\nexport class SummaryManager extends TypedEventEmitter<ISummarizerEvents> implements IDisposable {\n\tprivate readonly logger: ITelemetryLoggerExt;\n\tprivate readonly opsToBypassInitialDelay: number;\n\tprivate readonly initialDelayMs: number;\n\tprivate latestClientId: string | undefined;\n\tprivate state = SummaryManagerState.Off;\n\tprivate summarizer?: ISummarizer;\n\tprivate _disposed = false;\n\n\tpublic get disposed() {\n\t\treturn this._disposed;\n\t}\n\n\tpublic get currentState() {\n\t\treturn this.state;\n\t}\n\n\tconstructor(\n\t\tprivate readonly clientElection: ISummarizerClientElection,\n\t\tprivate readonly connectedState: IConnectedState,\n\t\tprivate readonly summaryCollection: Pick<\n\t\t\tSummaryCollection,\n\t\t\t\"opsSinceLastAck\" | \"addOpListener\" | \"removeOpListener\"\n\t\t>,\n\t\tparentLogger: ITelemetryBaseLogger,\n\t\t/** Creates summarizer by asking interactive container to spawn summarizing container and\n\t\t * get back its Summarizer instance. */\n\t\tprivate readonly requestSummarizerFn: () => Promise<ISummarizer>,\n\t\tprivate readonly startThrottler: IThrottler,\n\t\t{\n\t\t\tinitialDelayMs = defaultInitialDelayMs,\n\t\t\topsToBypassInitialDelay = defaultOpsToBypassInitialDelay,\n\t\t}: Readonly<Partial<ISummaryManagerConfig>> = {},\n\t\tprivate readonly disableHeuristics?: boolean,\n\t) {\n\t\tsuper();\n\n\t\tthis.logger = createChildLogger({\n\t\t\tlogger: parentLogger,\n\t\t\tnamespace: \"SummaryManager\",\n\t\t\tproperties: {\n\t\t\t\tall: { clientId: () => this.latestClientId },\n\t\t\t},\n\t\t});\n\n\t\tthis.connectedState.on(\"connected\", this.handleConnected);\n\t\tthis.connectedState.on(\"disconnected\", this.handleDisconnected);\n\t\tthis.latestClientId = this.connectedState.clientId;\n\n\t\tthis.opsToBypassInitialDelay = opsToBypassInitialDelay;\n\t\tthis.initialDelayMs = initialDelayMs;\n\t}\n\n\t/**\n\t * Until start is called, the SummaryManager won't begin attempting to start summarization. This ensures there's\n\t * a window between construction and starting where the caller can attach listeners.\n\t */\n\tpublic start(): void {\n\t\tthis.clientElection.on(\"electedSummarizerChanged\", this.refreshSummarizer);\n\t\tthis.refreshSummarizer();\n\t}\n\n\tprivate readonly handleConnected = (clientId: string) => {\n\t\tthis.latestClientId = clientId;\n\t\t// If we have a summarizer, it should have been either cancelled on disconnected by now.\n\t\t// But because of lastSummary process, it can still hang around, so there is not much we can\n\t\t// check or assert.\n\t\tthis.refreshSummarizer();\n\t};\n\n\tprivate readonly handleDisconnected = () => {\n\t\tthis.refreshSummarizer();\n\t};\n\n\tprivate readonly handleSummarizeEvent = (eventProps: ISummarizeEventProps) => {\n\t\tthis.emit(\"summarize\", eventProps);\n\t};\n\n\tprivate static readonly isStartingOrRunning = (state: SummaryManagerState) =>\n\t\tstate === SummaryManagerState.Starting || state === SummaryManagerState.Running;\n\n\tprivate getShouldSummarizeState(): ShouldSummarizeState {\n\t\t// Note that if we're in the Running state, the electedClient may be a summarizer client, so we can't\n\t\t// enforce connectedState.clientId === clientElection.electedClientId. But once we're Running, we should\n\t\t// only transition to Stopping when the electedParentId changes. Stopping the summarizer without\n\t\t// changing the electedParent will just cause us to transition to Starting again.\n\n\t\t// New Parent has been elected and it is not the current client, or\n\t\tif (this.connectedState.clientId !== this.clientElection.electedParentId) {\n\t\t\treturn { shouldSummarize: false, stopReason: \"notElectedParent\" };\n\t\t}\n\n\t\t// We are not already running the summarizer and we are not the current elected client id.\n\t\tif (\n\t\t\tthis.state !== SummaryManagerState.Running &&\n\t\t\tthis.connectedState.clientId !== this.clientElection.electedClientId\n\t\t) {\n\t\t\treturn { shouldSummarize: false, stopReason: \"notElectedClient\" };\n\t\t}\n\n\t\tif (!this.connectedState.connected) {\n\t\t\treturn { shouldSummarize: false, stopReason: \"parentNotConnected\" };\n\t\t}\n\n\t\tif (this.disposed) {\n\t\t\tassert(false, 0x260 /* \"Disposed should mean disconnected!\" */);\n\t\t} else {\n\t\t\treturn { shouldSummarize: true };\n\t\t}\n\t}\n\n\tprivate readonly refreshSummarizer = () => {\n\t\t// Transition states depending on shouldSummarize, which is a calculated property\n\t\t// that is only true if this client is connected and is the elected summarizer.\n\t\tconst shouldSummarizeState = this.getShouldSummarizeState();\n\t\tswitch (this.state) {\n\t\t\tcase SummaryManagerState.Off: {\n\t\t\t\tif (shouldSummarizeState.shouldSummarize) {\n\t\t\t\t\tthis.startSummarization();\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tcase SummaryManagerState.Starting: {\n\t\t\t\t// Cannot take any action until summarizer is created\n\t\t\t\t// state transition will occur after creation\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tcase SummaryManagerState.Running: {\n\t\t\t\tif (shouldSummarizeState.shouldSummarize === false) {\n\t\t\t\t\tthis.stop(shouldSummarizeState.stopReason);\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tcase SummaryManagerState.Stopping: {\n\t\t\t\t// Cannot take any action until running summarizer finishes\n\t\t\t\t// state transition will occur after it stops\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tdefault: {\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t};\n\n\tprivate startSummarization() {\n\t\tassert(this.state === SummaryManagerState.Off, 0x261 /* \"Expected: off\" */);\n\t\tthis.state = SummaryManagerState.Starting;\n\n\t\tassert(this.summarizer === undefined, 0x262 /* \"Old summarizer is still working!\" */);\n\n\t\tthis.delayBeforeCreatingSummarizer()\n\t\t\t.then(async (startWithInitialDelay: boolean) => {\n\t\t\t\t// Re-validate that it need to be running. Due to asynchrony, it may be not the case anymore\n\t\t\t\t// but only if creation was delayed. If it was not, then we want to ensure we always create\n\t\t\t\t// a summarizer to kick off lastSummary. Without that, we would not be able to summarize and get\n\t\t\t\t// document out of broken state if it has too many ops and ordering service keeps nacking main\n\t\t\t\t// container (and thus it goes into cycle of reconnects)\n\t\t\t\t// If we can't run the LastSummary, simply return as to avoid paying the cost of launching\n\t\t\t\t// the summarizer at all.\n\t\t\t\tconst shouldSummarizeStateEarlyStage = this.getShouldSummarizeState();\n\t\t\t\tif (\n\t\t\t\t\tstartWithInitialDelay &&\n\t\t\t\t\tshouldSummarizeStateEarlyStage.shouldSummarize === false\n\t\t\t\t) {\n\t\t\t\t\treturn `early exit ${shouldSummarizeStateEarlyStage.stopReason}`;\n\t\t\t\t}\n\n\t\t\t\t// We transition to Running before requesting the summarizer, because after requesting we can't predict\n\t\t\t\t// when the electedClient will be replaced with the new summarizer client.\n\t\t\t\t// The alternative would be to let connectedState.clientId !== clientElection.electedClientId when\n\t\t\t\t// state === Starting || state === Running.\n\t\t\t\tassert(\n\t\t\t\t\tthis.state === SummaryManagerState.Starting,\n\t\t\t\t\t0x263 /* \"Expected: starting\" */,\n\t\t\t\t);\n\t\t\t\tthis.state = SummaryManagerState.Running;\n\n\t\t\t\tconst summarizer = await this.requestSummarizerFn();\n\t\t\t\tthis.summarizer = summarizer;\n\t\t\t\tthis.summarizer.on(\"summarize\", this.handleSummarizeEvent);\n\n\t\t\t\t// Re-validate that it need to be running. Due to asynchrony, it may be not the case anymore\n\t\t\t\t// If we can't run the LastSummary, simply return as to avoid paying the cost of launching\n\t\t\t\t// the summarizer at all.\n\t\t\t\tconst shouldSummarizeState = this.getShouldSummarizeState();\n\t\t\t\tif (shouldSummarizeState.shouldSummarize === false) {\n\t\t\t\t\t// In order to allow the last summary to run, we not only need a stop reason that would\n\t\t\t\t\t// allow it but also, startWithInitialDelay to be false (start the summarization immediately),\n\t\t\t\t\t// which would happen when we have a high enough number of unsummarized ops.\n\t\t\t\t\tif (\n\t\t\t\t\t\tstartWithInitialDelay ||\n\t\t\t\t\t\t!Summarizer.stopReasonCanRunLastSummary(shouldSummarizeState.stopReason)\n\t\t\t\t\t) {\n\t\t\t\t\t\tthis.state = SummaryManagerState.Starting;\n\t\t\t\t\t\tsummarizer.stop(shouldSummarizeState.stopReason);\n\t\t\t\t\t\treturn `early exit after starting summarizer ${shouldSummarizeState.stopReason}`;\n\t\t\t\t\t}\n\t\t\t\t\tthis.logger.sendTelemetryEvent({\n\t\t\t\t\t\teventName: \"LastAttemptToSummarize\",\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n\t\t\t\tconst clientId = this.latestClientId!;\n\n\t\t\t\treturn PerformanceEvent.timedExecAsync(\n\t\t\t\t\tthis.logger,\n\t\t\t\t\t{ eventName: \"RunningSummarizer\", attempt: this.startThrottler.numAttempts },\n\t\t\t\t\tasync () => summarizer.run(clientId, this.disableHeuristics),\n\t\t\t\t);\n\t\t\t})\n\t\t\t.then((reason: string) => {\n\t\t\t\tthis.logger.sendTelemetryEvent({\n\t\t\t\t\teventName: \"EndingSummarizer\",\n\t\t\t\t\treason,\n\t\t\t\t});\n\t\t\t})\n\t\t\t.catch((error) => {\n\t\t\t\tthis.logger.sendTelemetryEvent(\n\t\t\t\t\t{\n\t\t\t\t\t\teventName: \"EndingSummarizer\",\n\t\t\t\t\t\treason: \"exception\",\n\t\t\t\t\t},\n\t\t\t\t\terror,\n\t\t\t\t);\n\n\t\t\t\t// Most of exceptions happen due to container being closed while loading it, due to\n\t\t\t\t// summarizer container loosing connection while load.\n\t\t\t\t// Not worth reporting such errors as errors. That said, we might miss some real errors if\n\t\t\t\t// we ignore blindly, so try to narrow signature we are looking for - skip logging\n\t\t\t\t// error only if this client should no longer be a summarizer (which in practice\n\t\t\t\t// means it also lost connection), and error happened on load (we do not have summarizer).\n\t\t\t\t// We could annotate the error raised in Container.load where the container closed during load with no error\n\t\t\t\t// and check for that case here, but that does not seem to be necessary.\n\t\t\t\tif (\n\t\t\t\t\tthis.getShouldSummarizeState().shouldSummarize ||\n\t\t\t\t\tthis.summarizer !== undefined\n\t\t\t\t) {\n\t\t\t\t\t// Report any failure as an error unless it was due to cancellation (like \"disconnected\" error)\n\t\t\t\t\t// If failure happened on container load, we may not yet realized that socket disconnected, so check\n\t\t\t\t\t// offlineError.\n\t\t\t\t\tconst category =\n\t\t\t\t\t\terror?.errorType === DriverErrorTypes.offlineError ? \"generic\" : \"error\";\n\t\t\t\t\tthis.logger.sendTelemetryEvent(\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\teventName: \"SummarizerException\",\n\t\t\t\t\t\t\tcategory,\n\t\t\t\t\t\t},\n\t\t\t\t\t\terror,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t})\n\t\t\t.finally(() => {\n\t\t\t\tassert(this.state !== SummaryManagerState.Off, 0x264 /* \"Expected: Not Off\" */);\n\t\t\t\tthis.state = SummaryManagerState.Off;\n\n\t\t\t\tthis.summarizer?.off(\"summarize\", this.handleSummarizeEvent);\n\t\t\t\tthis.summarizer?.close();\n\t\t\t\tthis.summarizer = undefined;\n\n\t\t\t\tif (this.getShouldSummarizeState().shouldSummarize) {\n\t\t\t\t\tthis.startSummarization();\n\t\t\t\t}\n\t\t\t});\n\t}\n\n\tprivate stop(reason: SummarizerStopReason) {\n\t\tif (!SummaryManager.isStartingOrRunning(this.state)) {\n\t\t\treturn;\n\t\t}\n\t\tthis.state = SummaryManagerState.Stopping;\n\n\t\t// Stopping the running summarizer client should trigger a change\n\t\t// in states when the running summarizer closes\n\t\tthis.summarizer?.stop(reason);\n\t}\n\n\t/**\n\t * Implements initial delay before creating summarizer\n\t * @returns `true`, if creation is delayed due to heuristics (not many ops to summarize).\n\t * `false` if summarizer should start immediately due to too many unsummarized ops.\n\t */\n\tprivate async delayBeforeCreatingSummarizer(): Promise<boolean> {\n\t\t// throttle creation of new summarizer containers to prevent spamming the server with websocket connections\n\t\tlet delayMs = this.startThrottler.getDelay();\n\n\t\t// We have been elected the summarizer. Some day we may be able to summarize with a live document but for\n\t\t// now we play it safe and launch a second copy.\n\t\tthis.logger.sendTelemetryEvent({\n\t\t\teventName: \"CreatingSummarizer\",\n\t\t\tthrottlerDelay: delayMs,\n\t\t\tinitialDelay: this.initialDelayMs,\n\t\t\tstartThrottlerMaxDelayMs: this.startThrottler.maxDelayMs,\n\t\t\topsSinceLastAck: this.summaryCollection.opsSinceLastAck,\n\t\t\topsToBypassInitialDelay: this.opsToBypassInitialDelay,\n\t\t\telectedParentId: this.clientElection.electedParentId,\n\t\t\telectedClientId: this.clientElection.electedClientId,\n\t\t});\n\n\t\t// This delay helps ensure that last summarizer that might be left from previous client\n\t\t// has enough time to complete its last summary and thus new summarizer not conflict with previous one.\n\t\t// If, however, there are too many unsummarized ops, try to resolve it as quickly as possible, with\n\t\t// understanding that we may see nacks because of such quick action.\n\t\t// A better design would be for summarizer election logic to always select current summarizer as\n\t\t// summarizing client (i.e. clientType === \"summarizer\" can be elected) to ensure that nobody else can\n\t\t// summarizer while it finishes its work and moves to exit.\n\t\t// It also helps with pure boot scenario (single client) to offset expensive work a bit out from\n\t\t// critical boot sequence.\n\t\tlet startWithInitialDelay = false;\n\t\tif (this.summaryCollection.opsSinceLastAck < this.opsToBypassInitialDelay) {\n\t\t\tstartWithInitialDelay = true;\n\t\t\tdelayMs = Math.max(delayMs, this.initialDelayMs);\n\t\t}\n\n\t\tif (delayMs > 0) {\n\t\t\tlet timer;\n\t\t\tlet resolveOpPromiseFn;\n\t\t\t// Create a listener that will break the delay if we've exceeded the initial delay ops count.\n\t\t\tconst opsListenerFn = () => {\n\t\t\t\tif (this.summaryCollection.opsSinceLastAck >= this.opsToBypassInitialDelay) {\n\t\t\t\t\tclearTimeout(timer);\n\t\t\t\t\tresolveOpPromiseFn();\n\t\t\t\t}\n\t\t\t};\n\t\t\t// Create a Promise that will resolve when the delay expires.\n\t\t\tconst delayPromise = new Promise<void>((resolve) => {\n\t\t\t\ttimer = setTimeout(() => resolve(), delayMs);\n\t\t\t});\n\t\t\t// Create a Promise that will resolve if the ops count passes the threshold.\n\t\t\tconst opPromise = new Promise<void>((resolve) => {\n\t\t\t\tresolveOpPromiseFn = resolve;\n\t\t\t});\n\t\t\tthis.summaryCollection.addOpListener(opsListenerFn);\n\t\t\tawait Promise.race([delayPromise, opPromise]);\n\t\t\tthis.summaryCollection.removeOpListener(opsListenerFn);\n\t\t}\n\t\treturn startWithInitialDelay;\n\t}\n\n\tpublic summarizeOnDemand(options: IOnDemandSummarizeOptions): ISummarizeResults {\n\t\tif (this.summarizer === undefined) {\n\t\t\tthrow Error(\"No running summarizer client\");\n\t\t\t// TODO: could spawn a summarizer client temporarily.\n\t\t}\n\t\treturn this.summarizer.summarizeOnDemand(options);\n\t}\n\n\tpublic enqueueSummarize(options: IEnqueueSummarizeOptions): EnqueueSummarizeResult {\n\t\tif (this.summarizer === undefined) {\n\t\t\tthrow Error(\"No running summarizer client\");\n\t\t\t// TODO: could spawn a summarizer client temporarily.\n\t\t}\n\t\treturn this.summarizer.enqueueSummarize(options);\n\t}\n\n\tpublic dispose() {\n\t\tthis.clientElection.off(\"electedSummarizerChanged\", this.refreshSummarizer);\n\t\tthis.connectedState.off(\"connected\", this.handleConnected);\n\t\tthis.connectedState.off(\"disconnected\", this.handleDisconnected);\n\t\tthis.summarizer?.off(\"summarize\", this.handleSummarizeEvent);\n\t\tthis._disposed = true;\n\t}\n}\n"]}
1
+ {"version":3,"file":"summaryManager.js","sourceRoot":"","sources":["../../src/summary/summaryManager.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport {\n\tIDisposable,\n\tIEvent,\n\tIEventProvider,\n\tITelemetryBaseLogger,\n} from \"@fluidframework/core-interfaces\";\nimport { assert } from \"@fluidframework/core-utils\";\nimport { TypedEventEmitter } from \"@fluid-internal/client-utils\";\nimport {\n\tcreateChildLogger,\n\tITelemetryLoggerExt,\n\tPerformanceEvent,\n} from \"@fluidframework/telemetry-utils\";\nimport { DriverErrorTypes } from \"@fluidframework/driver-definitions\";\nimport { IThrottler } from \"../throttler\";\nimport { ISummarizerClientElection } from \"./summarizerClientElection\";\nimport {\n\tEnqueueSummarizeResult,\n\tIEnqueueSummarizeOptions,\n\tIOnDemandSummarizeOptions,\n\tISummarizeEventProps,\n\tISummarizeResults,\n\tISummarizer,\n\tISummarizerEvents,\n\tSummarizerStopReason,\n} from \"./summarizerTypes\";\nimport { SummaryCollection } from \"./summaryCollection\";\nimport { Summarizer } from \"./summarizer\";\n\nconst defaultInitialDelayMs = 5000;\nconst defaultOpsToBypassInitialDelay = 4000;\n\nexport enum SummaryManagerState {\n\tOff = 0,\n\tStarting = 1,\n\tRunning = 2,\n\tStopping = 3,\n}\n\n// Please note that all reasons in this list are not errors,\n// and thus they are not raised today to parent container as error.\n// If this needs to be changed in future, we should re-evaluate what and how we raise to summarizer\ntype StopReason = Extract<\n\tSummarizerStopReason,\n\t\"parentNotConnected\" | \"notElectedParent\" | \"notElectedClient\"\n>;\ntype ShouldSummarizeState =\n\t| { shouldSummarize: true }\n\t| { shouldSummarize: false; stopReason: StopReason };\n\nexport interface IConnectedEvents extends IEvent {\n\t(event: \"connected\", listener: (clientId: string) => void);\n\t(event: \"disconnected\", listener: () => void);\n}\n\n/**\n * IConnectedState describes an object that SummaryManager can watch to observe connection/disconnection.\n *\n * Under current implementation, its role will be fulfilled by the ContainerRuntime, but this could be replaced\n * with anything else that fulfills the contract if we want to shift the layer that the SummaryManager lives at.\n */\nexport interface IConnectedState extends IEventProvider<IConnectedEvents> {\n\treadonly connected: boolean;\n\n\t/**\n\t * Under current implementation this is undefined if we've never connected, otherwise it's the clientId from our\n\t * latest connection (even if we've since disconnected!). Although this happens to be the behavior we want in\n\t * SummaryManager, I suspect that globally we may eventually want to modify this behavior (e.g. make clientId\n\t * undefined while disconnected). To protect against this, let's assume this field can't be trusted while\n\t * disconnected and instead separately track \"latest clientId\" in SummaryManager.\n\t */\n\treadonly clientId: string | undefined;\n}\n\nexport interface ISummaryManagerConfig {\n\tinitialDelayMs: number;\n\topsToBypassInitialDelay: number;\n}\n\n/**\n * SummaryManager is created by parent container (i.e. interactive container with clientType !== \"summarizer\") only.\n * It observes changes in calculated summarizer and reacts to changes by either creating summarizer client or\n * stopping existing summarizer client.\n */\nexport class SummaryManager extends TypedEventEmitter<ISummarizerEvents> implements IDisposable {\n\tprivate readonly logger: ITelemetryLoggerExt;\n\tprivate readonly opsToBypassInitialDelay: number;\n\tprivate readonly initialDelayMs: number;\n\tprivate latestClientId: string | undefined;\n\tprivate state = SummaryManagerState.Off;\n\tprivate summarizer?: ISummarizer;\n\tprivate _disposed = false;\n\n\tpublic get disposed() {\n\t\treturn this._disposed;\n\t}\n\n\tpublic get currentState() {\n\t\treturn this.state;\n\t}\n\n\tconstructor(\n\t\tprivate readonly clientElection: ISummarizerClientElection,\n\t\tprivate readonly connectedState: IConnectedState,\n\t\tprivate readonly summaryCollection: Pick<\n\t\t\tSummaryCollection,\n\t\t\t\"opsSinceLastAck\" | \"addOpListener\" | \"removeOpListener\"\n\t\t>,\n\t\tparentLogger: ITelemetryBaseLogger,\n\t\t/** Creates summarizer by asking interactive container to spawn summarizing container and\n\t\t * get back its Summarizer instance. */\n\t\tprivate readonly createSummarizerFn: () => Promise<ISummarizer>,\n\t\tprivate readonly startThrottler: IThrottler,\n\t\t{\n\t\t\tinitialDelayMs = defaultInitialDelayMs,\n\t\t\topsToBypassInitialDelay = defaultOpsToBypassInitialDelay,\n\t\t}: Readonly<Partial<ISummaryManagerConfig>> = {},\n\t\tprivate readonly disableHeuristics?: boolean,\n\t) {\n\t\tsuper();\n\n\t\tthis.logger = createChildLogger({\n\t\t\tlogger: parentLogger,\n\t\t\tnamespace: \"SummaryManager\",\n\t\t\tproperties: {\n\t\t\t\tall: { clientId: () => this.latestClientId },\n\t\t\t},\n\t\t});\n\n\t\tthis.connectedState.on(\"connected\", this.handleConnected);\n\t\tthis.connectedState.on(\"disconnected\", this.handleDisconnected);\n\t\tthis.latestClientId = this.connectedState.clientId;\n\n\t\tthis.opsToBypassInitialDelay = opsToBypassInitialDelay;\n\t\tthis.initialDelayMs = initialDelayMs;\n\t}\n\n\t/**\n\t * Until start is called, the SummaryManager won't begin attempting to start summarization. This ensures there's\n\t * a window between construction and starting where the caller can attach listeners.\n\t */\n\tpublic start(): void {\n\t\tthis.clientElection.on(\"electedSummarizerChanged\", this.refreshSummarizer);\n\t\tthis.refreshSummarizer();\n\t}\n\n\tprivate readonly handleConnected = (clientId: string) => {\n\t\tthis.latestClientId = clientId;\n\t\t// If we have a summarizer, it should have been either cancelled on disconnected by now.\n\t\t// But because of lastSummary process, it can still hang around, so there is not much we can\n\t\t// check or assert.\n\t\tthis.refreshSummarizer();\n\t};\n\n\tprivate readonly handleDisconnected = () => {\n\t\tthis.refreshSummarizer();\n\t};\n\n\tprivate readonly handleSummarizeEvent = (eventProps: ISummarizeEventProps) => {\n\t\tthis.emit(\"summarize\", eventProps);\n\t};\n\n\tprivate static readonly isStartingOrRunning = (state: SummaryManagerState) =>\n\t\tstate === SummaryManagerState.Starting || state === SummaryManagerState.Running;\n\n\tprivate getShouldSummarizeState(): ShouldSummarizeState {\n\t\t// Note that if we're in the Running state, the electedClient may be a summarizer client, so we can't\n\t\t// enforce connectedState.clientId === clientElection.electedClientId. But once we're Running, we should\n\t\t// only transition to Stopping when the electedParentId changes. Stopping the summarizer without\n\t\t// changing the electedParent will just cause us to transition to Starting again.\n\n\t\t// New Parent has been elected and it is not the current client, or\n\t\tif (this.connectedState.clientId !== this.clientElection.electedParentId) {\n\t\t\treturn { shouldSummarize: false, stopReason: \"notElectedParent\" };\n\t\t}\n\n\t\t// We are not already running the summarizer and we are not the current elected client id.\n\t\tif (\n\t\t\tthis.state !== SummaryManagerState.Running &&\n\t\t\tthis.connectedState.clientId !== this.clientElection.electedClientId\n\t\t) {\n\t\t\treturn { shouldSummarize: false, stopReason: \"notElectedClient\" };\n\t\t}\n\n\t\tif (!this.connectedState.connected) {\n\t\t\treturn { shouldSummarize: false, stopReason: \"parentNotConnected\" };\n\t\t}\n\n\t\tif (this.disposed) {\n\t\t\tassert(false, 0x260 /* \"Disposed should mean disconnected!\" */);\n\t\t} else {\n\t\t\treturn { shouldSummarize: true };\n\t\t}\n\t}\n\n\tprivate readonly refreshSummarizer = () => {\n\t\t// Transition states depending on shouldSummarize, which is a calculated property\n\t\t// that is only true if this client is connected and is the elected summarizer.\n\t\tconst shouldSummarizeState = this.getShouldSummarizeState();\n\t\tswitch (this.state) {\n\t\t\tcase SummaryManagerState.Off: {\n\t\t\t\tif (shouldSummarizeState.shouldSummarize) {\n\t\t\t\t\tthis.startSummarization();\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tcase SummaryManagerState.Starting: {\n\t\t\t\t// Cannot take any action until summarizer is created\n\t\t\t\t// state transition will occur after creation\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tcase SummaryManagerState.Running: {\n\t\t\t\tif (shouldSummarizeState.shouldSummarize === false) {\n\t\t\t\t\tthis.stop(shouldSummarizeState.stopReason);\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tcase SummaryManagerState.Stopping: {\n\t\t\t\t// Cannot take any action until running summarizer finishes\n\t\t\t\t// state transition will occur after it stops\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tdefault: {\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t};\n\n\tprivate startSummarization() {\n\t\tassert(this.state === SummaryManagerState.Off, 0x261 /* \"Expected: off\" */);\n\t\tthis.state = SummaryManagerState.Starting;\n\n\t\tassert(this.summarizer === undefined, 0x262 /* \"Old summarizer is still working!\" */);\n\n\t\tthis.delayBeforeCreatingSummarizer()\n\t\t\t.then(async (startWithInitialDelay: boolean) => {\n\t\t\t\t// Re-validate that it need to be running. Due to asynchrony, it may be not the case anymore\n\t\t\t\t// but only if creation was delayed. If it was not, then we want to ensure we always create\n\t\t\t\t// a summarizer to kick off lastSummary. Without that, we would not be able to summarize and get\n\t\t\t\t// document out of broken state if it has too many ops and ordering service keeps nacking main\n\t\t\t\t// container (and thus it goes into cycle of reconnects)\n\t\t\t\t// If we can't run the LastSummary, simply return as to avoid paying the cost of launching\n\t\t\t\t// the summarizer at all.\n\t\t\t\tconst shouldSummarizeStateEarlyStage = this.getShouldSummarizeState();\n\t\t\t\tif (\n\t\t\t\t\tstartWithInitialDelay &&\n\t\t\t\t\tshouldSummarizeStateEarlyStage.shouldSummarize === false\n\t\t\t\t) {\n\t\t\t\t\treturn `early exit ${shouldSummarizeStateEarlyStage.stopReason}`;\n\t\t\t\t}\n\n\t\t\t\t// We transition to Running before requesting the summarizer, because after requesting we can't predict\n\t\t\t\t// when the electedClient will be replaced with the new summarizer client.\n\t\t\t\t// The alternative would be to let connectedState.clientId !== clientElection.electedClientId when\n\t\t\t\t// state === Starting || state === Running.\n\t\t\t\tassert(\n\t\t\t\t\tthis.state === SummaryManagerState.Starting,\n\t\t\t\t\t0x263 /* \"Expected: starting\" */,\n\t\t\t\t);\n\t\t\t\tthis.state = SummaryManagerState.Running;\n\n\t\t\t\tconst summarizer = await this.createSummarizerFn();\n\t\t\t\tthis.summarizer = summarizer;\n\t\t\t\tthis.summarizer.on(\"summarize\", this.handleSummarizeEvent);\n\n\t\t\t\t// Re-validate that it need to be running. Due to asynchrony, it may be not the case anymore\n\t\t\t\t// If we can't run the LastSummary, simply return as to avoid paying the cost of launching\n\t\t\t\t// the summarizer at all.\n\t\t\t\tconst shouldSummarizeState = this.getShouldSummarizeState();\n\t\t\t\tif (shouldSummarizeState.shouldSummarize === false) {\n\t\t\t\t\t// In order to allow the last summary to run, we not only need a stop reason that would\n\t\t\t\t\t// allow it but also, startWithInitialDelay to be false (start the summarization immediately),\n\t\t\t\t\t// which would happen when we have a high enough number of unsummarized ops.\n\t\t\t\t\tif (\n\t\t\t\t\t\tstartWithInitialDelay ||\n\t\t\t\t\t\t!Summarizer.stopReasonCanRunLastSummary(shouldSummarizeState.stopReason)\n\t\t\t\t\t) {\n\t\t\t\t\t\tthis.state = SummaryManagerState.Starting;\n\t\t\t\t\t\tsummarizer.stop(shouldSummarizeState.stopReason);\n\t\t\t\t\t\treturn `early exit after starting summarizer ${shouldSummarizeState.stopReason}`;\n\t\t\t\t\t}\n\t\t\t\t\tthis.logger.sendTelemetryEvent({\n\t\t\t\t\t\teventName: \"LastAttemptToSummarize\",\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n\t\t\t\tconst clientId = this.latestClientId!;\n\n\t\t\t\treturn PerformanceEvent.timedExecAsync(\n\t\t\t\t\tthis.logger,\n\t\t\t\t\t{ eventName: \"RunningSummarizer\", attempt: this.startThrottler.numAttempts },\n\t\t\t\t\tasync () => summarizer.run(clientId, this.disableHeuristics),\n\t\t\t\t);\n\t\t\t})\n\t\t\t.then((reason: string) => {\n\t\t\t\tthis.logger.sendTelemetryEvent({\n\t\t\t\t\teventName: \"EndingSummarizer\",\n\t\t\t\t\treason,\n\t\t\t\t});\n\t\t\t})\n\t\t\t.catch((error) => {\n\t\t\t\tthis.logger.sendTelemetryEvent(\n\t\t\t\t\t{\n\t\t\t\t\t\teventName: \"EndingSummarizer\",\n\t\t\t\t\t\treason: \"exception\",\n\t\t\t\t\t},\n\t\t\t\t\terror,\n\t\t\t\t);\n\n\t\t\t\t// Most of exceptions happen due to container being closed while loading it, due to\n\t\t\t\t// summarizer container loosing connection while load.\n\t\t\t\t// Not worth reporting such errors as errors. That said, we might miss some real errors if\n\t\t\t\t// we ignore blindly, so try to narrow signature we are looking for - skip logging\n\t\t\t\t// error only if this client should no longer be a summarizer (which in practice\n\t\t\t\t// means it also lost connection), and error happened on load (we do not have summarizer).\n\t\t\t\t// We could annotate the error raised in Container.load where the container closed during load with no error\n\t\t\t\t// and check for that case here, but that does not seem to be necessary.\n\t\t\t\tif (\n\t\t\t\t\tthis.getShouldSummarizeState().shouldSummarize ||\n\t\t\t\t\tthis.summarizer !== undefined\n\t\t\t\t) {\n\t\t\t\t\t// Report any failure as an error unless it was due to cancellation (like \"disconnected\" error)\n\t\t\t\t\t// If failure happened on container load, we may not yet realized that socket disconnected, so check\n\t\t\t\t\t// offlineError.\n\t\t\t\t\tconst category =\n\t\t\t\t\t\terror?.errorType === DriverErrorTypes.offlineError ? \"generic\" : \"error\";\n\t\t\t\t\tthis.logger.sendTelemetryEvent(\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\teventName: \"SummarizerException\",\n\t\t\t\t\t\t\tcategory,\n\t\t\t\t\t\t},\n\t\t\t\t\t\terror,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t})\n\t\t\t.finally(() => {\n\t\t\t\tassert(this.state !== SummaryManagerState.Off, 0x264 /* \"Expected: Not Off\" */);\n\t\t\t\tthis.state = SummaryManagerState.Off;\n\n\t\t\t\tthis.summarizer?.off(\"summarize\", this.handleSummarizeEvent);\n\t\t\t\tthis.summarizer?.close();\n\t\t\t\tthis.summarizer = undefined;\n\n\t\t\t\tif (this.getShouldSummarizeState().shouldSummarize) {\n\t\t\t\t\tthis.startSummarization();\n\t\t\t\t}\n\t\t\t});\n\t}\n\n\tprivate stop(reason: SummarizerStopReason) {\n\t\tif (!SummaryManager.isStartingOrRunning(this.state)) {\n\t\t\treturn;\n\t\t}\n\t\tthis.state = SummaryManagerState.Stopping;\n\n\t\t// Stopping the running summarizer client should trigger a change\n\t\t// in states when the running summarizer closes\n\t\tthis.summarizer?.stop(reason);\n\t}\n\n\t/**\n\t * Implements initial delay before creating summarizer\n\t * @returns `true`, if creation is delayed due to heuristics (not many ops to summarize).\n\t * `false` if summarizer should start immediately due to too many unsummarized ops.\n\t */\n\tprivate async delayBeforeCreatingSummarizer(): Promise<boolean> {\n\t\t// throttle creation of new summarizer containers to prevent spamming the server with websocket connections\n\t\tlet delayMs = this.startThrottler.getDelay();\n\n\t\t// We have been elected the summarizer. Some day we may be able to summarize with a live document but for\n\t\t// now we play it safe and launch a second copy.\n\t\tthis.logger.sendTelemetryEvent({\n\t\t\teventName: \"CreatingSummarizer\",\n\t\t\tthrottlerDelay: delayMs,\n\t\t\tinitialDelay: this.initialDelayMs,\n\t\t\tstartThrottlerMaxDelayMs: this.startThrottler.maxDelayMs,\n\t\t\topsSinceLastAck: this.summaryCollection.opsSinceLastAck,\n\t\t\topsToBypassInitialDelay: this.opsToBypassInitialDelay,\n\t\t\telectedParentId: this.clientElection.electedParentId,\n\t\t\telectedClientId: this.clientElection.electedClientId,\n\t\t});\n\n\t\t// This delay helps ensure that last summarizer that might be left from previous client\n\t\t// has enough time to complete its last summary and thus new summarizer not conflict with previous one.\n\t\t// If, however, there are too many unsummarized ops, try to resolve it as quickly as possible, with\n\t\t// understanding that we may see nacks because of such quick action.\n\t\t// A better design would be for summarizer election logic to always select current summarizer as\n\t\t// summarizing client (i.e. clientType === \"summarizer\" can be elected) to ensure that nobody else can\n\t\t// summarizer while it finishes its work and moves to exit.\n\t\t// It also helps with pure boot scenario (single client) to offset expensive work a bit out from\n\t\t// critical boot sequence.\n\t\tlet startWithInitialDelay = false;\n\t\tif (this.summaryCollection.opsSinceLastAck < this.opsToBypassInitialDelay) {\n\t\t\tstartWithInitialDelay = true;\n\t\t\tdelayMs = Math.max(delayMs, this.initialDelayMs);\n\t\t}\n\n\t\tif (delayMs > 0) {\n\t\t\tlet timer;\n\t\t\tlet resolveOpPromiseFn;\n\t\t\t// Create a listener that will break the delay if we've exceeded the initial delay ops count.\n\t\t\tconst opsListenerFn = () => {\n\t\t\t\tif (this.summaryCollection.opsSinceLastAck >= this.opsToBypassInitialDelay) {\n\t\t\t\t\tclearTimeout(timer);\n\t\t\t\t\tresolveOpPromiseFn();\n\t\t\t\t}\n\t\t\t};\n\t\t\t// Create a Promise that will resolve when the delay expires.\n\t\t\tconst delayPromise = new Promise<void>((resolve) => {\n\t\t\t\ttimer = setTimeout(() => resolve(), delayMs);\n\t\t\t});\n\t\t\t// Create a Promise that will resolve if the ops count passes the threshold.\n\t\t\tconst opPromise = new Promise<void>((resolve) => {\n\t\t\t\tresolveOpPromiseFn = resolve;\n\t\t\t});\n\t\t\tthis.summaryCollection.addOpListener(opsListenerFn);\n\t\t\tawait Promise.race([delayPromise, opPromise]);\n\t\t\tthis.summaryCollection.removeOpListener(opsListenerFn);\n\t\t}\n\t\treturn startWithInitialDelay;\n\t}\n\n\tpublic summarizeOnDemand(options: IOnDemandSummarizeOptions): ISummarizeResults {\n\t\tif (this.summarizer === undefined) {\n\t\t\tthrow Error(\"No running summarizer client\");\n\t\t\t// TODO: could spawn a summarizer client temporarily.\n\t\t}\n\t\treturn this.summarizer.summarizeOnDemand(options);\n\t}\n\n\tpublic enqueueSummarize(options: IEnqueueSummarizeOptions): EnqueueSummarizeResult {\n\t\tif (this.summarizer === undefined) {\n\t\t\tthrow Error(\"No running summarizer client\");\n\t\t\t// TODO: could spawn a summarizer client temporarily.\n\t\t}\n\t\treturn this.summarizer.enqueueSummarize(options);\n\t}\n\n\tpublic dispose() {\n\t\tthis.clientElection.off(\"electedSummarizerChanged\", this.refreshSummarizer);\n\t\tthis.connectedState.off(\"connected\", this.handleConnected);\n\t\tthis.connectedState.off(\"disconnected\", this.handleDisconnected);\n\t\tthis.summarizer?.off(\"summarize\", this.handleSummarizeEvent);\n\t\tthis._disposed = true;\n\t}\n}\n"]}
package/dist/throttler.js CHANGED
@@ -10,22 +10,6 @@ exports.formLinearFnWithAttemptOffset = exports.formLinearFn = exports.formExpon
10
10
  * Delay is based on previous attempts within specified time window, subtracting delay time.
11
11
  */
12
12
  class Throttler {
13
- constructor(
14
- /** Width of sliding delay window in milliseconds. */
15
- delayWindowMs,
16
- /** Maximum delay allowed in milliseconds. */
17
- maxDelayMs,
18
- /**
19
- * Delay function used to calculate what the delay should be.
20
- * The input is the number of attempts that occurred within the sliding window.
21
- * The result is the calculated delay in milliseconds.
22
- */
23
- delayFn) {
24
- this.delayWindowMs = delayWindowMs;
25
- this.maxDelayMs = maxDelayMs;
26
- this.delayFn = delayFn;
27
- this.startTimes = [];
28
- }
29
13
  get numAttempts() {
30
14
  return this.startTimes.length;
31
15
  }
@@ -43,6 +27,22 @@ class Throttler {
43
27
  get latestAttemptTime() {
44
28
  return this.startTimes.length > 0 ? this.startTimes[this.startTimes.length - 1] : undefined;
45
29
  }
30
+ constructor(
31
+ /** Width of sliding delay window in milliseconds. */
32
+ delayWindowMs,
33
+ /** Maximum delay allowed in milliseconds. */
34
+ maxDelayMs,
35
+ /**
36
+ * Delay function used to calculate what the delay should be.
37
+ * The input is the number of attempts that occurred within the sliding window.
38
+ * The result is the calculated delay in milliseconds.
39
+ */
40
+ delayFn) {
41
+ this.delayWindowMs = delayWindowMs;
42
+ this.maxDelayMs = maxDelayMs;
43
+ this.delayFn = delayFn;
44
+ this.startTimes = [];
45
+ }
46
46
  getDelay() {
47
47
  const now = Date.now();
48
48
  const latestAttemptTime = this.latestAttemptTime;
@@ -1 +1 @@
1
- {"version":3,"file":"throttler.js","sourceRoot":"","sources":["../src/throttler.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nexport interface IThrottler {\n\t/**\n\t * Computes what the throttle delay should be, and records an attempt\n\t * which will be used for calculating future attempt delays.\n\t */\n\tgetDelay(): number;\n\n\t/**\n\t * Number of attempts that occurred within the sliding window as of\n\t * the most recent delay computation.\n\t */\n\treadonly numAttempts: number;\n\n\t/** Width of sliding delay window in milliseconds. */\n\treadonly delayWindowMs: number;\n\t/** Maximum delay allowed in milliseconds. */\n\treadonly maxDelayMs: number;\n\t/**\n\t * Delay function used to calculate what the delay should be.\n\t * The input is the number of attempts that occurred within the sliding window.\n\t * The result is the calculated delay in milliseconds.\n\t */\n\treadonly delayFn: (numAttempts: number) => number;\n}\n\n/**\n * Used to give increasing delay times for throttling a single functionality.\n * Delay is based on previous attempts within specified time window, subtracting delay time.\n */\nexport class Throttler implements IThrottler {\n\tprivate startTimes: number[] = [];\n\n\tpublic get numAttempts() {\n\t\treturn this.startTimes.length;\n\t}\n\n\t/**\n\t * Gets all attempt start times after compensating for the delay times\n\t * by adding the delay times to the actual times.\n\t */\n\tpublic getAttempts(): readonly number[] {\n\t\treturn [...this.startTimes];\n\t}\n\n\t/**\n\t * Latest attempt time after compensating for the delay time itself\n\t * by adding the delay time to the actual time.\n\t */\n\tpublic get latestAttemptTime() {\n\t\treturn this.startTimes.length > 0 ? this.startTimes[this.startTimes.length - 1] : undefined;\n\t}\n\n\tconstructor(\n\t\t/** Width of sliding delay window in milliseconds. */\n\t\tpublic readonly delayWindowMs: number,\n\t\t/** Maximum delay allowed in milliseconds. */\n\t\tpublic readonly maxDelayMs: number,\n\t\t/**\n\t\t * Delay function used to calculate what the delay should be.\n\t\t * The input is the number of attempts that occurred within the sliding window.\n\t\t * The result is the calculated delay in milliseconds.\n\t\t */\n\t\tpublic readonly delayFn: (numAttempts: number) => number,\n\t) {}\n\n\tpublic getDelay() {\n\t\tconst now = Date.now();\n\n\t\tconst latestAttemptTime = this.latestAttemptTime;\n\t\tif (latestAttemptTime !== undefined) {\n\t\t\t// If getDelay was called sooner than the most recent delay,\n\t\t\t// subtract the remaining time, since we previously added it.\n\t\t\tconst earlyMs = latestAttemptTime - now;\n\t\t\tif (earlyMs > 0) {\n\t\t\t\tthis.startTimes = this.startTimes.map((t) => t - earlyMs);\n\t\t\t}\n\t\t}\n\n\t\t// Remove all attempts that have already fallen out of the window.\n\t\tthis.startTimes = this.startTimes.filter((t) => now - t < this.delayWindowMs);\n\n\t\t// Compute delay, but do not exceed the specified max delay.\n\t\tconst delayMs = Math.min(this.delayFn(this.startTimes.length), this.maxDelayMs);\n\n\t\t// Record this attempt start time.\n\t\tthis.startTimes.push(now);\n\n\t\t// Account for the delay time, by effectively removing it from the delay window.\n\t\tthis.startTimes = this.startTimes.map((t) => t + delayMs);\n\n\t\tif (delayMs === this.maxDelayMs) {\n\t\t\t// We hit max delay, so adding more won't affect anything.\n\t\t\t// Shift off oldest time to stop this array from growing forever.\n\t\t\tthis.startTimes.shift();\n\t\t}\n\n\t\treturn delayMs;\n\t}\n}\n\n/**\n * Helper function to generate simple exponential throttle functions.\n * f(n) = [coefficient] x ([multiplier]^n) + [flatOffset]\n * where n = number of attempts, and f(n) = delay time in milliseconds.\n * If not provided, coefficient will default to 1, multiplier to 2,\n * minimum delay to 0, and the offset to 0, yielding:\n * 0 ms, 2 ms, 4 ms, 8 ms, ..., 2^n ms\n * where M = multiplier; an exponential back-off.\n * Use initialDelay to decide what should happen when numAttempts is 0,\n * leave it undefined to not special case.\n */\nexport const formExponentialFn =\n\t({\n\t\tmultiplier = 2,\n\t\tcoefficient = 1,\n\t\toffset = 0,\n\t\tinitialDelay = undefined as number | undefined,\n\t} = {}): IThrottler[\"delayFn\"] =>\n\t(numAttempts) =>\n\t\tMath.max(\n\t\t\t0,\n\t\t\tnumAttempts <= 0 && initialDelay !== undefined\n\t\t\t\t? initialDelay\n\t\t\t\t: coefficient * Math.pow(multiplier, numAttempts) + offset,\n\t\t);\n\n/** f(n) = C x (B^(n+A)) + F = (C x B^A) x B^n + F */\nexport const formExponentialFnWithAttemptOffset = (\n\tattemptOffset: number,\n\t{\n\t\tmultiplier = 2,\n\t\tcoefficient = 1,\n\t\toffset = 0,\n\t\tinitialDelay = undefined as number | undefined,\n\t} = {},\n) =>\n\tformExponentialFn({\n\t\tmultiplier,\n\t\tcoefficient: coefficient * Math.pow(multiplier, attemptOffset),\n\t\toffset,\n\t\tinitialDelay,\n\t});\n\n/**\n * Helper function to generate simple linear throttle functions.\n * f(n) = [coefficient] x n + [flatOffset]\n * where n = number of attempts, and f(n) = delay time in milliseconds.\n * If not provided, coefficient will default to 1, and offset to 0, yielding:\n * 0 ms, 1 ms, 2 ms, 3 ms, ..., n ms delays; a linear back-off.\n */\nexport const formLinearFn =\n\t({ coefficient = 1, offset = 0 } = {}): IThrottler[\"delayFn\"] =>\n\t(numAttempts) =>\n\t\tMath.max(0, coefficient * numAttempts + offset);\n\n/** f(n) = C x (n+A) + F = C x n + (C x A + F) */\nexport const formLinearFnWithAttemptOffset = (\n\tattemptOffset: number,\n\t{ coefficient = 1, offset = 0 } = {},\n) =>\n\tformLinearFn({\n\t\tcoefficient,\n\t\toffset: coefficient * attemptOffset + offset,\n\t});\n"]}
1
+ {"version":3,"file":"throttler.js","sourceRoot":"","sources":["../src/throttler.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nexport interface IThrottler {\n\t/**\n\t * Computes what the throttle delay should be, and records an attempt\n\t * which will be used for calculating future attempt delays.\n\t */\n\tgetDelay(): number;\n\n\t/**\n\t * Number of attempts that occurred within the sliding window as of\n\t * the most recent delay computation.\n\t */\n\treadonly numAttempts: number;\n\n\t/** Width of sliding delay window in milliseconds. */\n\treadonly delayWindowMs: number;\n\t/** Maximum delay allowed in milliseconds. */\n\treadonly maxDelayMs: number;\n\t/**\n\t * Delay function used to calculate what the delay should be.\n\t * The input is the number of attempts that occurred within the sliding window.\n\t * The result is the calculated delay in milliseconds.\n\t */\n\treadonly delayFn: (numAttempts: number) => number;\n}\n\n/**\n * Used to give increasing delay times for throttling a single functionality.\n * Delay is based on previous attempts within specified time window, subtracting delay time.\n */\nexport class Throttler implements IThrottler {\n\tprivate startTimes: number[] = [];\n\n\tpublic get numAttempts() {\n\t\treturn this.startTimes.length;\n\t}\n\n\t/**\n\t * Gets all attempt start times after compensating for the delay times\n\t * by adding the delay times to the actual times.\n\t */\n\tpublic getAttempts(): readonly number[] {\n\t\treturn [...this.startTimes];\n\t}\n\n\t/**\n\t * Latest attempt time after compensating for the delay time itself\n\t * by adding the delay time to the actual time.\n\t */\n\tpublic get latestAttemptTime() {\n\t\treturn this.startTimes.length > 0 ? this.startTimes[this.startTimes.length - 1] : undefined;\n\t}\n\n\tconstructor(\n\t\t/** Width of sliding delay window in milliseconds. */\n\t\tpublic readonly delayWindowMs: number,\n\t\t/** Maximum delay allowed in milliseconds. */\n\t\tpublic readonly maxDelayMs: number,\n\t\t/**\n\t\t * Delay function used to calculate what the delay should be.\n\t\t * The input is the number of attempts that occurred within the sliding window.\n\t\t * The result is the calculated delay in milliseconds.\n\t\t */\n\t\tpublic readonly delayFn: (numAttempts: number) => number,\n\t) {}\n\n\tpublic getDelay() {\n\t\tconst now = Date.now();\n\n\t\tconst latestAttemptTime = this.latestAttemptTime;\n\t\tif (latestAttemptTime !== undefined) {\n\t\t\t// If getDelay was called sooner than the most recent delay,\n\t\t\t// subtract the remaining time, since we previously added it.\n\t\t\tconst earlyMs = latestAttemptTime - now;\n\t\t\tif (earlyMs > 0) {\n\t\t\t\tthis.startTimes = this.startTimes.map((t) => t - earlyMs);\n\t\t\t}\n\t\t}\n\n\t\t// Remove all attempts that have already fallen out of the window.\n\t\tthis.startTimes = this.startTimes.filter((t) => now - t < this.delayWindowMs);\n\n\t\t// Compute delay, but do not exceed the specified max delay.\n\t\tconst delayMs = Math.min(this.delayFn(this.startTimes.length), this.maxDelayMs);\n\n\t\t// Record this attempt start time.\n\t\tthis.startTimes.push(now);\n\n\t\t// Account for the delay time, by effectively removing it from the delay window.\n\t\tthis.startTimes = this.startTimes.map((t) => t + delayMs);\n\n\t\tif (delayMs === this.maxDelayMs) {\n\t\t\t// We hit max delay, so adding more won't affect anything.\n\t\t\t// Shift off oldest time to stop this array from growing forever.\n\t\t\tthis.startTimes.shift();\n\t\t}\n\n\t\treturn delayMs;\n\t}\n}\n\n/**\n * Helper function to generate simple exponential throttle functions.\n * f(n) = [coefficient] x ([multiplier]^n) + [flatOffset]\n * where n = number of attempts, and f(n) = delay time in milliseconds.\n * If not provided, coefficient will default to 1, multiplier to 2,\n * minimum delay to 0, and the offset to 0, yielding:\n * 0 ms, 2 ms, 4 ms, 8 ms, ..., 2^n ms\n * where M = multiplier; an exponential back-off.\n * Use initialDelay to decide what should happen when numAttempts is 0,\n * leave it undefined to not special case.\n */\nexport const formExponentialFn =\n\t({\n\t\tmultiplier = 2,\n\t\tcoefficient = 1,\n\t\toffset = 0,\n\t\tinitialDelay = undefined as number | undefined,\n\t} = {}): IThrottler[\"delayFn\"] =>\n\t(numAttempts) =>\n\t\tMath.max(\n\t\t\t0,\n\t\t\tnumAttempts <= 0 && initialDelay !== undefined\n\t\t\t\t? initialDelay\n\t\t\t\t: coefficient * Math.pow(multiplier, numAttempts) + offset,\n\t\t);\n\n/** f(n) = C x (B^(n+A)) + F = (C x B^A) x B^n + F */\nexport const formExponentialFnWithAttemptOffset = (\n\tattemptOffset: number,\n\t{\n\t\tmultiplier = 2,\n\t\tcoefficient = 1,\n\t\toffset = 0,\n\t\tinitialDelay = undefined as number | undefined,\n\t} = {},\n) =>\n\tformExponentialFn({\n\t\tmultiplier,\n\t\tcoefficient: coefficient * Math.pow(multiplier, attemptOffset),\n\t\toffset,\n\t\tinitialDelay,\n\t});\n\n/**\n * Helper function to generate simple linear throttle functions.\n * f(n) = [coefficient] x n + [flatOffset]\n * where n = number of attempts, and f(n) = delay time in milliseconds.\n * If not provided, coefficient will default to 1, and offset to 0, yielding:\n * 0 ms, 1 ms, 2 ms, 3 ms, ..., n ms delays; a linear back-off.\n */\nexport const formLinearFn =\n\t({ coefficient = 1, offset = 0 } = {}): IThrottler[\"delayFn\"] =>\n\t(numAttempts) =>\n\t\tMath.max(0, coefficient * numAttempts + offset);\n\n/** f(n) = C x (n+A) + F = C x n + (C x A + F) */\nexport const formLinearFnWithAttemptOffset = (\n\tattemptOffset: number,\n\t{ coefficient = 1, offset = 0 } = {},\n) =>\n\tformLinearFn({\n\t\tcoefficient,\n\t\toffset: coefficient * attemptOffset + offset,\n\t});\n"]}
@@ -5,7 +5,7 @@
5
5
  "toolPackages": [
6
6
  {
7
7
  "packageName": "@microsoft/api-extractor",
8
- "packageVersion": "7.34.9"
8
+ "packageVersion": "7.38.0"
9
9
  }
10
10
  ]
11
11
  }
@@ -32,12 +32,13 @@ export declare class BlobHandle implements IFluidHandle<ArrayBufferLike> {
32
32
  }
33
33
  /**
34
34
  * Information from a snapshot needed to load BlobManager
35
+ * @public
35
36
  */
36
37
  export interface IBlobManagerLoadInfo {
37
38
  ids?: string[];
38
39
  redirectTable?: [string, string][];
39
40
  }
40
- export declare type IBlobManagerRuntime = Pick<IContainerRuntime, "attachState" | "connected" | "logger" | "clientDetails"> & Pick<ContainerRuntime, "gcTombstoneEnforcementAllowed"> & TypedEventEmitter<IContainerRuntimeEvents>;
41
+ export type IBlobManagerRuntime = Pick<IContainerRuntime, "attachState" | "connected" | "logger" | "clientDetails"> & Pick<ContainerRuntime, "gcTombstoneEnforcementAllowed"> & TypedEventEmitter<IContainerRuntimeEvents>;
41
42
  export interface IPendingBlobs {
42
43
  [id: string]: {
43
44
  blob: string;
@@ -79,7 +80,6 @@ export declare class BlobManager extends TypedEventEmitter<IBlobManagerEvents> {
79
80
  * because we know that the server will not delete the blob corresponding to that storage ID.
80
81
  */
81
82
  private readonly opsInFlight;
82
- private readonly retryThrottler;
83
83
  /** If true, throw an error when a tombstone attachment blob is retrieved. */
84
84
  private readonly throwOnTombstoneLoad;
85
85
  /**
@@ -103,6 +103,7 @@ export declare class BlobManager extends TypedEventEmitter<IBlobManagerEvents> {
103
103
  get allBlobsAttached(): boolean;
104
104
  get hasPendingBlobs(): boolean;
105
105
  private createAbortError;
106
+ hasPendingStashedBlobs(): boolean;
106
107
  /**
107
108
  * Upload blobs added while offline. This must be completed before connecting and resubmitting ops.
108
109
  */
@@ -125,7 +126,6 @@ export declare class BlobManager extends TypedEventEmitter<IBlobManagerEvents> {
125
126
  private deletePendingBlobMaybe;
126
127
  private deletePendingBlob;
127
128
  private onUploadResolve;
128
- private onUploadReject;
129
129
  /**
130
130
  * Resubmit a BlobAttach op. Used to add storage IDs to ops that were
131
131
  * submitted to runtime while disconnected.
@@ -188,6 +188,6 @@ export declare class BlobManager extends TypedEventEmitter<IBlobManagerEvents> {
188
188
  */
189
189
  private verifyBlobValidity;
190
190
  setRedirectTable(table: Map<string, string>): void;
191
- getPendingBlobs(waitBlobsToAttach?: boolean): Promise<IPendingBlobs | undefined>;
191
+ attachAndGetPendingBlobs(): Promise<IPendingBlobs | undefined>;
192
192
  }
193
193
  //# sourceMappingURL=blobManager.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"blobManager.d.ts","sourceRoot":"","sources":["../src/blobManager.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"blobManager.d.ts","sourceRoot":"","sources":["../src/blobManager.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,YAAY,EAAE,mBAAmB,EAAE,MAAM,iCAAiC,CAAC;AACpF,OAAO,EAAE,uBAAuB,EAAE,MAAM,oCAAoC,CAAC;AAC7E,OAAO,EAEN,yBAAyB,EACzB,aAAa,EACb,MAAM,sCAAsC,CAAC;AAQ9C,OAAO,EAAkC,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AACjG,OAAO,EACN,iBAAiB,EACjB,uBAAuB,EACvB,MAAM,+CAA+C,CAAC;AACvD,OAAO,EAAe,uBAAuB,EAAE,MAAM,uCAAuC,CAAC;AAS7F,OAAO,EACN,sBAAsB,EACtB,qBAAqB,EACrB,iBAAiB,EACjB,MAAM,qCAAqC,CAAC;AAG7C,OAAO,EAAE,gBAAgB,EAA8B,MAAM,oBAAoB,CAAC;AASlF;;;;;;GAMG;AACH,qBAAa,UAAW,YAAW,YAAY,CAAC,eAAe,CAAC;aAc9C,IAAI,EAAE,MAAM;aACZ,YAAY,EAAE,mBAAmB;IAC1C,GAAG,EAAE,MAAM,OAAO,CAAC,GAAG,CAAC;IAC9B,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAC;IAhBhC,OAAO,CAAC,QAAQ,CAAkB;IAElC,IAAW,YAAY,IAAI,YAAY,CAEtC;IAED,IAAW,UAAU,IAAI,OAAO,CAE/B;IAED,SAAgB,YAAY,EAAE,MAAM,CAAC;gBAGpB,IAAI,EAAE,MAAM,EACZ,YAAY,EAAE,mBAAmB,EAC1C,GAAG,EAAE,MAAM,OAAO,CAAC,GAAG,CAAC,EACb,aAAa,CAAC,SAAQ,IAAI,aAAA;IAKrC,WAAW;IAOX,IAAI,CAAC,MAAM,EAAE,YAAY;CAGhC;AAED;;;GAGG;AACH,MAAM,WAAW,oBAAoB;IACpC,GAAG,CAAC,EAAE,MAAM,EAAE,CAAC;IACf,aAAa,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC;CACnC;AAID,MAAM,MAAM,mBAAmB,GAAG,IAAI,CACrC,iBAAiB,EACjB,aAAa,GAAG,WAAW,GAAG,QAAQ,GAAG,eAAe,CACxD,GACA,IAAI,CAAC,gBAAgB,EAAE,+BAA+B,CAAC,GACvD,iBAAiB,CAAC,uBAAuB,CAAC,CAAC;AAmB5C,MAAM,WAAW,aAAa;IAC7B,CAAC,EAAE,EAAE,MAAM,GAAG;QACb,IAAI,EAAE,MAAM,CAAC;QACb,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,eAAe,CAAC,EAAE,MAAM,CAAC;QACzB,QAAQ,CAAC,EAAE,OAAO,CAAC;QACnB,KAAK,CAAC,EAAE,OAAO,CAAC;KAChB,CAAC;CACF;AAED,MAAM,WAAW,kBAAkB;IAClC,CAAC,KAAK,EAAE,gBAAgB,EAAE,QAAQ,EAAE,MAAM,IAAI,OAAE;CAChD;AAED,qBAAa,WAAY,SAAQ,iBAAiB,CAAC,kBAAkB,CAAC;IAqCpE,OAAO,CAAC,QAAQ,CAAC,YAAY;IAE7B,OAAO,CAAC,QAAQ,CAAC,UAAU;IAc3B,OAAO,CAAC,QAAQ,CAAC,aAAa;IAG9B,OAAO,CAAC,QAAQ,CAAC,aAAa;IAC9B,OAAO,CAAC,QAAQ,CAAC,OAAO;IAExB,OAAO,CAAC,QAAQ,CAAC,cAAc;IA1DhC,gBAAuB,QAAQ,YAAY;IAC3C,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,qBAAqB,CAAoB;IACjE,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAoB;IAEvC;;;;;;OAMG;IACH,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAkC;IAEhE;;OAEG;IACH,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAuC;IAEpE;;;;OAIG;IACH,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAoC;IAEhE,6EAA6E;IAC7E,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CAAU;IAC/C;;;OAGG;IACH,OAAO,CAAC,QAAQ,CAAC,eAAe,CAA0B;IAE1D,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAgD;gBAG/D,YAAY,EAAE,mBAAmB,EAClD,QAAQ,EAAE,oBAAoB,EACb,UAAU,EAAE,MAAM,uBAAuB;IAC1D;;;;;;;;;OASG;IACH,gBAAgB,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,KAAK,IAAI,EAG9C,aAAa,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,EAGzC,aAAa,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,EAC5C,OAAO,EAAE,mBAAmB,EAC7C,YAAY,2BAAoB,EACf,cAAc,EAAE,CAAC,KAAK,CAAC,EAAE,uBAAuB,KAAK,IAAI;IAuF3E,IAAW,gBAAgB,IAAI,OAAO,CAOrC;IAED,IAAW,eAAe,IAAI,OAAO,CAKpC;IAED,OAAO,CAAC,gBAAgB;IAOjB,sBAAsB,IAAI,OAAO;IAGxC;;OAEG;IACU,qBAAqB;IAelC;;;OAGG;IACH,OAAO,KAAK,UAAU,GAerB;IAEY,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC;IAmC9D,OAAO,CAAC,aAAa;YAqBP,kBAAkB;IAUnB,UAAU,CACtB,IAAI,EAAE,eAAe,EACrB,MAAM,CAAC,EAAE,WAAW,GAClB,OAAO,CAAC,YAAY,CAAC,eAAe,CAAC,CAAC;YA6C3B,UAAU;IAwCxB;;;OAGG;IACH,OAAO,CAAC,cAAc;IAItB,OAAO,CAAC,sBAAsB;IAS9B,OAAO,CAAC,iBAAiB;IAMzB,OAAO,CAAC,eAAe;IAyCvB;;;;OAIG;IACI,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS;IAiBtD,mBAAmB,CAAC,OAAO,EAAE,yBAAyB,EAAE,KAAK,EAAE,OAAO;IAuD7E;;;;;OAKG;WACiB,IAAI,CACvB,SAAS,EAAE,aAAa,GAAG,SAAS,EACpC,YAAY,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC,GACvD,OAAO,CAAC,oBAAoB,CAAC;IAehC;;OAEG;IACH,OAAO,CAAC,IAAI;IAgBL,SAAS,CAAC,gBAAgB,CAAC,EAAE,iBAAiB,GAAG,qBAAqB;IA2B7E;;;;;OAKG;IACI,SAAS,CAAC,MAAM,GAAE,OAAe,GAAG,sBAAsB;IAejE;;;OAGG;IACI,kBAAkB,CAAC,YAAY,EAAE,MAAM,EAAE,GAAG,IAAI;IAIvD;;;;;OAKG;IACI,qBAAqB,CAAC,oBAAoB,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE;IAUtE;;;;;;;;;;OAUG;IACH,OAAO,CAAC,4BAA4B;IAwCpC;;;;OAIG;IACI,sBAAsB,CAAC,gBAAgB,EAAE,MAAM,EAAE;IAsBxD;;;OAGG;IACH,OAAO,CAAC,kBAAkB;IAiDnB,gBAAgB,CAAC,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC;IAoBrC,wBAAwB,IAAI,OAAO,CAAC,aAAa,GAAG,SAAS,CAAC;CAsD3E"}
@@ -7,10 +7,10 @@ import { createResponseError, generateHandleContextPath, responseToException, Su
7
7
  import { assert, Deferred } from "@fluidframework/core-utils";
8
8
  import { bufferToString, stringToBuffer, TypedEventEmitter } from "@fluid-internal/client-utils";
9
9
  import { AttachState } from "@fluidframework/container-definitions";
10
- import { createChildMonitoringContext, GenericError, LoggingError, PerformanceEvent, } from "@fluidframework/telemetry-utils";
10
+ import { createChildMonitoringContext, GenericError, LoggingError, PerformanceEvent, wrapError, } from "@fluidframework/telemetry-utils";
11
+ import { canRetryOnError, runWithRetry } from "@fluidframework/driver-utils";
11
12
  import { TombstoneResponseHeaderKey } from "./containerRuntime";
12
13
  import { sendGCUnexpectedUsageEvent, disableAttachmentBlobSweepKey, throwOnTombstoneLoadKey, } from "./gc";
13
- import { Throttler, formExponentialFn } from "./throttler";
14
14
  import { summarizerClientType } from "./summary";
15
15
  /**
16
16
  * This class represents blob (long string)
@@ -20,6 +20,12 @@ import { summarizerClientType } from "./summary";
20
20
  * and loads blob.
21
21
  */
22
22
  export class BlobHandle {
23
+ get IFluidHandle() {
24
+ return this;
25
+ }
26
+ get isAttached() {
27
+ return this.routeContext.isAttached && this.attached;
28
+ }
23
29
  constructor(path, routeContext, get, onAttachGraph) {
24
30
  this.path = path;
25
31
  this.routeContext = routeContext;
@@ -28,12 +34,6 @@ export class BlobHandle {
28
34
  this.attached = false;
29
35
  this.absolutePath = generateHandleContextPath(path, this.routeContext);
30
36
  }
31
- get IFluidHandle() {
32
- return this;
33
- }
34
- get isAttached() {
35
- return this.routeContext.isAttached && this.attached;
36
- }
37
37
  attachGraph() {
38
38
  if (!this.attached) {
39
39
  this.attached = true;
@@ -44,22 +44,6 @@ export class BlobHandle {
44
44
  throw new Error("Cannot bind to blob handle");
45
45
  }
46
46
  }
47
- class CancellableThrottler {
48
- constructor(throttler) {
49
- this.throttler = throttler;
50
- this.cancelP = new Deferred();
51
- }
52
- async getDelay() {
53
- return Promise.race([
54
- this.cancelP.promise,
55
- new Promise((resolve) => setTimeout(resolve, this.throttler.getDelay())),
56
- ]);
57
- }
58
- cancel() {
59
- this.cancelP.resolve();
60
- this.cancelP = new Deferred();
61
- }
62
- }
63
47
  export class BlobManager extends TypedEventEmitter {
64
48
  constructor(routeContext, snapshot, getStorage,
65
49
  /**
@@ -96,10 +80,6 @@ export class BlobManager extends TypedEventEmitter {
96
80
  * because we know that the server will not delete the blob corresponding to that storage ID.
97
81
  */
98
82
  this.opsInFlight = new Map();
99
- this.retryThrottler = new CancellableThrottler(new Throttler(60 * 1000, // 60 sec delay window
100
- 30 * 1000, // 30 sec max delay
101
- // throttling function increases exponentially (0ms, 40ms, 80ms, 160ms, etc)
102
- formExponentialFn({ coefficient: 20, initialDelay: 0 })));
103
83
  /**
104
84
  * This stores IDs of tombstoned blobs.
105
85
  * Tombstone is a temporary feature that imitates a blob getting swept by garbage collection.
@@ -148,6 +128,7 @@ export class BlobManager extends TypedEventEmitter {
148
128
  attached,
149
129
  acked,
150
130
  opsent: true,
131
+ pendingStashed: true,
151
132
  });
152
133
  });
153
134
  this.sendBlobAttachOp = (localId, blobId) => {
@@ -193,13 +174,15 @@ export class BlobManager extends TypedEventEmitter {
193
174
  uploadTime: pending?.uploadTime,
194
175
  });
195
176
  }
177
+ hasPendingStashedBlobs() {
178
+ return Array.from(this.pendingBlobs.values()).some((e) => e.pendingStashed === true);
179
+ }
196
180
  /**
197
181
  * Upload blobs added while offline. This must be completed before connecting and resubmitting ops.
198
182
  */
199
183
  async processStashedChanges() {
200
- this.retryThrottler.cancel();
201
184
  const pendingUploads = Array.from(this.pendingBlobs.values())
202
- .filter((e) => e.uploading === true)
185
+ .filter((e) => e.pendingStashed === true)
203
186
  .map(async (e) => e.uploadP);
204
187
  await PerformanceEvent.timedExecAsync(this.mc.logger, {
205
188
  eventName: "BlobUploadProcessStashedChanges",
@@ -303,7 +286,27 @@ export class BlobManager extends TypedEventEmitter {
303
286
  });
304
287
  }
305
288
  async uploadBlob(localId, blob) {
306
- return PerformanceEvent.timedExecAsync(this.mc.logger, { eventName: "createBlob" }, async () => this.getStorage().createBlob(blob), { end: true, cancel: this.runtime.connected ? "error" : "generic" }).then((response) => this.onUploadResolve(localId, response), async (err) => this.onUploadReject(localId, err));
289
+ return runWithRetry(async () => {
290
+ try {
291
+ return await this.getStorage().createBlob(blob);
292
+ }
293
+ catch (error) {
294
+ const entry = this.pendingBlobs.get(localId);
295
+ assert(!!entry, 0x387 /* Must have pending blob entry for blob which failed to upload */);
296
+ if (entry.opsent && !canRetryOnError(error)) {
297
+ throw wrapError(error, () => new LoggingError(`uploadBlob error`, { canRetry: true }));
298
+ }
299
+ throw error;
300
+ }
301
+ }, "createBlob", this.mc.logger, {
302
+ cancel: this.pendingBlobs.get(localId)?.abortSignal,
303
+ }).then((response) => this.onUploadResolve(localId, response), (error) => {
304
+ // it will only reject if we haven't sent an op
305
+ // and is a non-retriable error. It will only reject
306
+ // the promise but not throw any error outside.
307
+ this.pendingBlobs.get(localId)?.handleP.reject(error);
308
+ this.deletePendingBlob(localId);
309
+ });
307
310
  }
308
311
  /**
309
312
  * Set up a mapping in the redirect table from fromId to toId. Also, notify the runtime that a reference is added
@@ -360,25 +363,6 @@ export class BlobManager extends TypedEventEmitter {
360
363
  }
361
364
  return response;
362
365
  }
363
- async onUploadReject(localId, error) {
364
- const entry = this.pendingBlobs.get(localId);
365
- assert(!!entry, 0x387 /* Must have pending blob entry for blob which failed to upload */);
366
- if (entry.abortSignal?.aborted === true && !entry.opsent) {
367
- this.deletePendingBlob(localId);
368
- return;
369
- }
370
- if (!this.runtime.connected) {
371
- // we are probably not connected to storage but start another upload request in case we are
372
- entry.uploadP = this.retryThrottler
373
- .getDelay()
374
- .then(async () => this.uploadBlob(localId, entry.blob));
375
- return entry.uploadP;
376
- }
377
- else {
378
- entry.handleP.reject(error);
379
- throw error;
380
- }
381
- }
382
366
  /**
383
367
  * Resubmit a BlobAttach op. Used to add storage IDs to ops that were
384
368
  * submitted to runtime while disconnected.
@@ -405,6 +389,9 @@ export class BlobManager extends TypedEventEmitter {
405
389
  this.deletePendingBlob(localId);
406
390
  return;
407
391
  }
392
+ if (pendingEntry?.pendingStashed) {
393
+ pendingEntry.pendingStashed = false;
394
+ }
408
395
  }
409
396
  assert(blobId !== undefined, 0x12a /* "Missing blob id on metadata" */);
410
397
  // Set up a mapping from local ID to storage ID. This is crucial since without this the blob cannot be
@@ -655,7 +642,7 @@ export class BlobManager extends TypedEventEmitter {
655
642
  this.setRedirection(storageId, storageId);
656
643
  }
657
644
  }
658
- async getPendingBlobs(waitBlobsToAttach) {
645
+ async attachAndGetPendingBlobs() {
659
646
  return PerformanceEvent.timedExecAsync(this.mc.logger, { eventName: "GetPendingBlobs" }, async () => {
660
647
  if (this.pendingBlobs.size === 0) {
661
648
  return;
@@ -667,33 +654,30 @@ export class BlobManager extends TypedEventEmitter {
667
654
  for (const [id, entry] of this.pendingBlobs) {
668
655
  if (!localBlobs.has(entry)) {
669
656
  localBlobs.add(entry);
670
- if (waitBlobsToAttach) {
671
- if (!entry.opsent) {
672
- this.sendBlobAttachOp(id, entry.storageId);
673
- }
674
- entry.handleP.resolve(this.getBlobHandle(id));
675
- attachBlobsP.push(new Promise((resolve) => {
676
- const onBlobAttached = (attachedEntry) => {
677
- if (attachedEntry === entry) {
678
- this.off("blobAttached", onBlobAttached);
679
- resolve();
680
- }
681
- };
682
- if (!entry.attached) {
683
- this.on("blobAttached", onBlobAttached);
684
- }
685
- else {
657
+ if (!entry.opsent) {
658
+ this.sendBlobAttachOp(id, entry.storageId);
659
+ }
660
+ entry.handleP.resolve(this.getBlobHandle(id));
661
+ attachBlobsP.push(new Promise((resolve) => {
662
+ const onBlobAttached = (attachedEntry) => {
663
+ if (attachedEntry === entry) {
664
+ this.off("blobAttached", onBlobAttached);
686
665
  resolve();
687
666
  }
688
- }));
689
- }
667
+ };
668
+ if (!entry.attached) {
669
+ this.on("blobAttached", onBlobAttached);
670
+ }
671
+ else {
672
+ resolve();
673
+ }
674
+ }));
690
675
  }
691
676
  }
692
677
  await Promise.all(attachBlobsP);
693
678
  }
694
- // another for is needed to correctly mark attach state
695
- // future optimization won't add unattached blobs to the list
696
679
  for (const [id, entry] of this.pendingBlobs) {
680
+ assert(entry.attached === true, 0x790 /* stashed blob should be attached */);
697
681
  blobs[id] = {
698
682
  blob: bufferToString(entry.blob, "base64"),
699
683
  storageId: entry.storageId,
@@ -703,7 +687,7 @@ export class BlobManager extends TypedEventEmitter {
703
687
  uploadTime: entry.uploadTime,
704
688
  };
705
689
  }
706
- return blobs;
690
+ return Object.keys(blobs).length > 0 ? blobs : undefined;
707
691
  });
708
692
  }
709
693
  }