@fluidframework/container-runtime 0.54.2 → 0.56.0-49831

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 (94) hide show
  1. package/.eslintrc.js +1 -1
  2. package/dist/blobManager.js +1 -1
  3. package/dist/blobManager.js.map +1 -1
  4. package/dist/containerRuntime.d.ts +20 -14
  5. package/dist/containerRuntime.d.ts.map +1 -1
  6. package/dist/containerRuntime.js +51 -58
  7. package/dist/containerRuntime.js.map +1 -1
  8. package/dist/dataStoreContext.d.ts +57 -33
  9. package/dist/dataStoreContext.d.ts.map +1 -1
  10. package/dist/dataStoreContext.js +44 -54
  11. package/dist/dataStoreContext.js.map +1 -1
  12. package/dist/dataStores.d.ts +12 -2
  13. package/dist/dataStores.d.ts.map +1 -1
  14. package/dist/dataStores.js +106 -32
  15. package/dist/dataStores.js.map +1 -1
  16. package/dist/garbageCollection.d.ts +49 -14
  17. package/dist/garbageCollection.d.ts.map +1 -1
  18. package/dist/garbageCollection.js +122 -26
  19. package/dist/garbageCollection.js.map +1 -1
  20. package/dist/index.d.ts +7 -7
  21. package/dist/index.d.ts.map +1 -1
  22. package/dist/index.js +12 -17
  23. package/dist/index.js.map +1 -1
  24. package/dist/packageVersion.d.ts +1 -1
  25. package/dist/packageVersion.d.ts.map +1 -1
  26. package/dist/packageVersion.js +1 -1
  27. package/dist/packageVersion.js.map +1 -1
  28. package/dist/runningSummarizer.d.ts.map +1 -1
  29. package/dist/runningSummarizer.js +2 -9
  30. package/dist/runningSummarizer.js.map +1 -1
  31. package/dist/summaryFormat.d.ts +2 -0
  32. package/dist/summaryFormat.d.ts.map +1 -1
  33. package/dist/summaryFormat.js +2 -4
  34. package/dist/summaryFormat.js.map +1 -1
  35. package/dist/summaryGenerator.d.ts +0 -5
  36. package/dist/summaryGenerator.d.ts.map +1 -1
  37. package/dist/summaryGenerator.js.map +1 -1
  38. package/dist/summaryManager.d.ts +1 -0
  39. package/dist/summaryManager.d.ts.map +1 -1
  40. package/dist/summaryManager.js +7 -2
  41. package/dist/summaryManager.js.map +1 -1
  42. package/garbageCollection.md +33 -0
  43. package/lib/blobManager.js +1 -1
  44. package/lib/blobManager.js.map +1 -1
  45. package/lib/containerRuntime.d.ts +20 -14
  46. package/lib/containerRuntime.d.ts.map +1 -1
  47. package/lib/containerRuntime.js +51 -58
  48. package/lib/containerRuntime.js.map +1 -1
  49. package/lib/dataStoreContext.d.ts +57 -33
  50. package/lib/dataStoreContext.d.ts.map +1 -1
  51. package/lib/dataStoreContext.js +42 -52
  52. package/lib/dataStoreContext.js.map +1 -1
  53. package/lib/dataStores.d.ts +12 -2
  54. package/lib/dataStores.d.ts.map +1 -1
  55. package/lib/dataStores.js +107 -33
  56. package/lib/dataStores.js.map +1 -1
  57. package/lib/garbageCollection.d.ts +49 -14
  58. package/lib/garbageCollection.d.ts.map +1 -1
  59. package/lib/garbageCollection.js +122 -26
  60. package/lib/garbageCollection.js.map +1 -1
  61. package/lib/index.d.ts +7 -7
  62. package/lib/index.d.ts.map +1 -1
  63. package/lib/index.js +6 -7
  64. package/lib/index.js.map +1 -1
  65. package/lib/packageVersion.d.ts +1 -1
  66. package/lib/packageVersion.d.ts.map +1 -1
  67. package/lib/packageVersion.js +1 -1
  68. package/lib/packageVersion.js.map +1 -1
  69. package/lib/runningSummarizer.d.ts.map +1 -1
  70. package/lib/runningSummarizer.js +2 -9
  71. package/lib/runningSummarizer.js.map +1 -1
  72. package/lib/summaryFormat.d.ts +2 -0
  73. package/lib/summaryFormat.d.ts.map +1 -1
  74. package/lib/summaryFormat.js +2 -4
  75. package/lib/summaryFormat.js.map +1 -1
  76. package/lib/summaryGenerator.d.ts +0 -5
  77. package/lib/summaryGenerator.d.ts.map +1 -1
  78. package/lib/summaryGenerator.js.map +1 -1
  79. package/lib/summaryManager.d.ts +1 -0
  80. package/lib/summaryManager.d.ts.map +1 -1
  81. package/lib/summaryManager.js +7 -2
  82. package/lib/summaryManager.js.map +1 -1
  83. package/package.json +24 -23
  84. package/src/blobManager.ts +1 -1
  85. package/src/containerRuntime.ts +69 -65
  86. package/src/dataStoreContext.ts +105 -129
  87. package/src/dataStores.ts +118 -68
  88. package/src/garbageCollection.ts +156 -31
  89. package/src/index.ts +52 -6
  90. package/src/packageVersion.ts +1 -1
  91. package/src/runningSummarizer.ts +2 -7
  92. package/src/summaryFormat.ts +4 -4
  93. package/src/summaryGenerator.ts +0 -5
  94. package/src/summaryManager.ts +9 -3
@@ -1 +1 @@
1
- {"version":3,"file":"summaryManager.js","sourceRoot":"","sources":["../src/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 { IDisposable, IEvent, IEventProvider, ITelemetryLogger } from \"@fluidframework/common-definitions\";\nimport { TypedEventEmitter, assert } from \"@fluidframework/common-utils\";\nimport { ChildLogger, PerformanceEvent } from \"@fluidframework/telemetry-utils\";\nimport { DriverErrorType } from \"@fluidframework/driver-definitions\";\nimport { createSummarizingWarning } from \"./summarizer\";\nimport { ISummarizerClientElection } from \"./summarizerClientElection\";\nimport { IThrottler } from \"./throttler\";\nimport {\n ISummarizer,\n ISummarizerOptions,\n ISummarizingWarning,\n SummarizerStopReason,\n} from \"./summarizerTypes\";\nimport { SummaryCollection } from \"./summaryCollection\";\n\nconst defaultInitialDelayMs = 5000;\nconst defaultOpsToBypassInitialDelay = 4000;\n\nexport enum SummaryManagerState {\n Off = 0,\n Starting = 1,\n Running = 2,\n Stopping = 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<SummarizerStopReason, \"parentNotConnected\" | \"parentShouldNotSummarize\">;\ntype ShouldSummarizeState =\n | { shouldSummarize: true; }\n | { shouldSummarize: false; stopReason: StopReason; };\n\nexport interface IConnectedEvents extends IEvent {\n (event: \"connected\", listener: (clientId: string) => void);\n (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 readonly connected: boolean;\n\n /**\n * Under current implementation this is undefined if we've never connected, otherwise it's the clientId from our\n * latest connection (even if we've since disconnected!). Although this happens to be the behavior we want in\n * SummaryManager, I suspect that globally we may eventually want to modify this behavior (e.g. make clientId\n * undefined while disconnected). To protect against this, let's assume this field can't be trusted while\n * disconnected and instead separately track \"latest clientId\" in SummaryManager.\n */\n readonly clientId: string | undefined;\n}\n\nexport interface ISummaryManagerEvents extends IEvent {\n (event: \"summarizerWarning\", listener: (warning: ISummarizingWarning) => void);\n}\n\nexport interface ISummaryManagerConfig {\n initialDelayMs: number;\n opsToBypassInitialDelay: 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<ISummaryManagerEvents> implements IDisposable {\n private readonly logger: ITelemetryLogger;\n private readonly opsToBypassInitialDelay: number;\n private readonly initialDelayMs: number;\n private latestClientId: string | undefined;\n private state = SummaryManagerState.Off;\n private summarizer?: ISummarizer;\n private _disposed = false;\n\n public get disposed() {\n return this._disposed;\n }\n\n public get currentState() { return this.state; }\n\n constructor(\n private readonly clientElection: ISummarizerClientElection,\n private readonly connectedState: IConnectedState,\n private readonly summaryCollection:\n Pick<SummaryCollection, \"opsSinceLastAck\" | \"addOpListener\" | \"removeOpListener\">,\n parentLogger: ITelemetryLogger,\n /** Creates summarizer by asking interactive container to spawn summarizing container and\n * get back its Summarizer instance. */\n private readonly requestSummarizerFn: () => Promise<ISummarizer>,\n private readonly startThrottler: IThrottler,\n {\n initialDelayMs = defaultInitialDelayMs,\n opsToBypassInitialDelay = defaultOpsToBypassInitialDelay,\n }: Readonly<Partial<ISummaryManagerConfig>> = {},\n private readonly summarizerOptions?: Readonly<Partial<ISummarizerOptions>>,\n ) {\n super();\n\n this.logger = ChildLogger.create(\n parentLogger,\n \"SummaryManager\",\n {all:{ clientId: () => this.latestClientId }});\n\n this.connectedState.on(\"connected\", this.handleConnected);\n this.connectedState.on(\"disconnected\", this.handleDisconnected);\n this.latestClientId = this.connectedState.clientId;\n\n this.opsToBypassInitialDelay = opsToBypassInitialDelay;\n this.initialDelayMs = initialDelayMs;\n }\n\n /**\n * Until start is called, the SummaryManager won't begin attempting to start summarization. This ensures there's\n * a window between construction and starting where the caller can attach listeners.\n */\n public start(): void {\n this.clientElection.on(\"electedSummarizerChanged\", this.refreshSummarizer);\n this.refreshSummarizer();\n }\n\n private readonly handleConnected = (clientId: string) => {\n this.latestClientId = clientId;\n // If we have a summarizer, it should have been either cancelled on disconnected by now.\n // But because of lastSummary process, it can still hang around, so there is not much we can\n // check or assert.\n this.refreshSummarizer();\n };\n\n private readonly handleDisconnected = () => {\n this.refreshSummarizer();\n };\n\n private getShouldSummarizeState(): ShouldSummarizeState {\n if (!this.connectedState.connected) {\n return { shouldSummarize: false, stopReason: \"parentNotConnected\" };\n } else if (this.connectedState.clientId !== this.clientElection.electedClientId) {\n return { shouldSummarize: false, stopReason: \"parentShouldNotSummarize\" };\n } else if (this.disposed) {\n assert(false, 0x260 /* \"Disposed should mean disconnected!\" */);\n } else {\n return { shouldSummarize: true };\n }\n }\n\n private readonly refreshSummarizer = () => {\n // Transition states depending on shouldSummarize, which is a calculated property\n // that is only true if this client is connected and is the elected summarizer.\n const shouldSummarizeState = this.getShouldSummarizeState();\n switch (this.state) {\n case SummaryManagerState.Off: {\n if (shouldSummarizeState.shouldSummarize) {\n this.startSummarization();\n }\n return;\n }\n case SummaryManagerState.Starting: {\n // Cannot take any action until summarizer is created\n // state transition will occur after creation\n return;\n }\n case SummaryManagerState.Running: {\n if (shouldSummarizeState.shouldSummarize === false) {\n this.stop(shouldSummarizeState.stopReason);\n }\n return;\n }\n case SummaryManagerState.Stopping: {\n // Cannot take any action until running summarizer finishes\n // state transition will occur after it stops\n return;\n }\n default: {\n return;\n }\n }\n };\n\n private startSummarization() {\n assert(this.state === SummaryManagerState.Off, 0x261 /* \"Expected: off\" */);\n this.state = SummaryManagerState.Starting;\n\n assert(this.summarizer === undefined, 0x262 /* \"Old summarizer is still working!\" */);\n\n let reason = \"unknown\";\n\n this.delayBeforeCreatingSummarizer().then(async (startWithInitialDelay: boolean) => {\n // Re-validate that it need to be running. Due to asynchrony, it may be not the case anymore\n // but only if creation was delayed. If it was not, then we want to ensure we always create\n // a summarizer to kick off lastSummary. Without that, we would not be able to summarize and get\n // document out of broken state if it has too many ops and ordering service keeps nacking main\n // container (and thus it goes into cycle of reconnects)\n if (startWithInitialDelay && this.getShouldSummarizeState().shouldSummarize === false) {\n return;\n }\n\n const summarizer = await this.requestSummarizerFn();\n\n // Re-validate that it need to be running. Due to asynchrony, it may be not the case anymore\n const shouldSummarizeState = this.getShouldSummarizeState();\n if (shouldSummarizeState.shouldSummarize === false) {\n summarizer.stop(shouldSummarizeState.stopReason);\n return;\n }\n\n assert(this.state === SummaryManagerState.Starting, 0x263 /* \"Expected: starting\" */);\n this.state = SummaryManagerState.Running;\n\n summarizer.on(\"summarizingError\",\n (warning: ISummarizingWarning) => this.emit(\"summarizerWarning\", warning));\n this.summarizer = summarizer;\n\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n const clientId = this.latestClientId!;\n\n reason = await PerformanceEvent.timedExecAsync(\n this.logger,\n { eventName: \"RunningSummarizer\", attempt: this.startThrottler.numAttempts },\n async () => summarizer.run(clientId, this.summarizerOptions),\n );\n }).catch((error) => {\n // Most of exceptions happen due to container being closed while loading it, due to\n // summarizer container loosing connection while load.\n // Not worth reporting such errors as errors. That said, we might miss some real errors if\n // we ignore blindly, so try to narrow signature we are looking for - skip logging\n // error only if this client should no longer be a summarizer (which in practice\n // means it also lost connection), and error happened on load (we do not have summarizer).\n // We could add error.fluidErrorCode !== \"containerClosedWithoutErrorDuringLoad\" check to narrow it down,\n // but that does not seem to be necessary.\n if (this.getShouldSummarizeState().shouldSummarize || this.summarizer !== undefined) {\n // Report any failure as an error unless it was due to cancellation (like \"disconnected\" error)\n // If failure happened on container load, we may not yet realized that socket disconnected, so check\n // offlineError.\n const category = error?.errorType === DriverErrorType.offlineError ? \"generic\" : \"error\";\n this.logger.sendTelemetryEvent(\n {\n eventName: \"SummarizerException\",\n category,\n },\n error);\n this.emit(\"summarizerWarning\", error);\n\n // Note that summarizer may keep going (like doing last summary).\n // Ideally we await stopping process, but this code path is due to a bug\n // that needs to be fixed either way.\n this.stop(\"summarizerException\");\n }\n }).finally(() => {\n assert(this.state !== SummaryManagerState.Off, 0x264 /* \"Expected: Not Off\" */);\n this.state = SummaryManagerState.Off;\n\n this.summarizer = undefined;\n\n this.logger.sendTelemetryEvent({\n eventName: \"EndingSummarizer\",\n reason,\n });\n\n if (this.getShouldSummarizeState().shouldSummarize) {\n this.startSummarization();\n }\n });\n }\n\n private stop(reason: SummarizerStopReason) {\n assert(this.state === SummaryManagerState.Running || this.state === SummaryManagerState.Starting,\n 0x265 /* \"Expected: Starting or Running\" */);\n this.state = SummaryManagerState.Stopping;\n\n // Stopping the running summarizer client should trigger a change\n // in states when the running summarizer closes\n this.summarizer?.stop(reason);\n }\n\n /**\n * Implements initial delay before creating summarizer\n * @returns true, if creation is delayed due to heuristics (not many ops to summarize).\n * False if summarizer should start immediately due to too many unsummarized ops.\n */\n private async delayBeforeCreatingSummarizer(): Promise<boolean> {\n // throttle creation of new summarizer containers to prevent spamming the server with websocket connections\n let delayMs = this.startThrottler.getDelay();\n if (delayMs > 0 && delayMs > this.startThrottler.maxDelayMs) {\n this.emit(\n \"summarizerWarning\",\n createSummarizingWarning(\"summaryManagerCreateSummarizerMaxThrottleDelay\", false),\n );\n }\n\n // We have been elected the summarizer. Some day we may be able to summarize with a live document but for\n // now we play it safe and launch a second copy.\n this.logger.sendTelemetryEvent({\n eventName: \"CreatingSummarizer\",\n throttlerDelay: delayMs,\n initialDelay: this.initialDelayMs,\n opsSinceLastAck: this.summaryCollection.opsSinceLastAck,\n opsToBypassInitialDelay: this.opsToBypassInitialDelay,\n });\n\n // This delay helps ensure that last summarizer that might be left from previous client\n // has enough time to complete its last summary and thus new summarizer not conflict with previous one.\n // If, however, there are too many unsummarized ops, try to resolve it as quickly as possible, with\n // understanding that we may see nacks because of such quick action.\n // A better design would be for summarizer election logic to always select current summarizer as\n // summarizing client (i.e. clientType === \"summarizer\" can be elected) to ensure that nobody else can\n // summarizer while it finishes its work and moves to exit.\n // It also helps with pure boot scenario (single client) to offset expensive work a bit out from\n // critical boot sequence.\n let startWithInitialDelay = false;\n if (this.summaryCollection.opsSinceLastAck < this.opsToBypassInitialDelay) {\n startWithInitialDelay = true;\n delayMs = Math.max(delayMs, this.initialDelayMs);\n }\n\n if (delayMs > 0) {\n let timer;\n let resolveOpPromiseFn;\n // Create a listener that will break the delay if we've exceeded the initial delay ops count.\n const opsListenerFn = () => {\n if (this.summaryCollection.opsSinceLastAck >= this.opsToBypassInitialDelay) {\n clearTimeout(timer);\n resolveOpPromiseFn();\n }\n };\n // Create a Promise that will resolve when the delay expires.\n const delayPromise = new Promise<void>((resolve) => {\n timer = setTimeout(() => resolve(), delayMs);\n });\n // Create a Promise that will resolve if the ops count passes the threshold.\n const opPromise = new Promise<void>((resolve) => { resolveOpPromiseFn = resolve; });\n this.summaryCollection.addOpListener(opsListenerFn);\n await Promise.race([ delayPromise, opPromise ]);\n this.summaryCollection.removeOpListener(opsListenerFn);\n }\n return startWithInitialDelay;\n }\n\n public readonly summarizeOnDemand: ISummarizer[\"summarizeOnDemand\"] = (...args) => {\n if (this.summarizer === undefined) {\n throw Error(\"No running summarizer client\");\n // TODO: could spawn a summarizer client temporarily.\n }\n return this.summarizer.summarizeOnDemand(...args);\n };\n\n public readonly enqueueSummarize: ISummarizer[\"enqueueSummarize\"] = (...args) => {\n if (this.summarizer === undefined) {\n throw Error(\"No running summarizer client\");\n // TODO: could spawn a summarizer client temporarily.\n }\n return this.summarizer.enqueueSummarize(...args);\n };\n\n public dispose() {\n this.clientElection.off(\"electedSummarizerChanged\", this.refreshSummarizer);\n this.connectedState.off(\"connected\", this.handleConnected);\n this.connectedState.off(\"disconnected\", this.handleDisconnected);\n this._disposed = true;\n }\n}\n"]}
1
+ {"version":3,"file":"summaryManager.js","sourceRoot":"","sources":["../src/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 { IDisposable, IEvent, IEventProvider, ITelemetryLogger } from \"@fluidframework/common-definitions\";\nimport { TypedEventEmitter, assert } from \"@fluidframework/common-utils\";\nimport { ChildLogger, PerformanceEvent } from \"@fluidframework/telemetry-utils\";\nimport { DriverErrorType } from \"@fluidframework/driver-definitions\";\nimport { createSummarizingWarning } from \"./summarizer\";\nimport { ISummarizerClientElection } from \"./summarizerClientElection\";\nimport { IThrottler } from \"./throttler\";\nimport {\n ISummarizer,\n ISummarizerOptions,\n ISummarizingWarning,\n SummarizerStopReason,\n} from \"./summarizerTypes\";\nimport { SummaryCollection } from \"./summaryCollection\";\n\nconst defaultInitialDelayMs = 5000;\nconst defaultOpsToBypassInitialDelay = 4000;\n\nexport enum SummaryManagerState {\n Off = 0,\n Starting = 1,\n Running = 2,\n Stopping = 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<SummarizerStopReason, \"parentNotConnected\" | \"parentShouldNotSummarize\">;\ntype ShouldSummarizeState =\n | { shouldSummarize: true; }\n | { shouldSummarize: false; stopReason: StopReason; };\n\nexport interface IConnectedEvents extends IEvent {\n (event: \"connected\", listener: (clientId: string) => void);\n (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 readonly connected: boolean;\n\n /**\n * Under current implementation this is undefined if we've never connected, otherwise it's the clientId from our\n * latest connection (even if we've since disconnected!). Although this happens to be the behavior we want in\n * SummaryManager, I suspect that globally we may eventually want to modify this behavior (e.g. make clientId\n * undefined while disconnected). To protect against this, let's assume this field can't be trusted while\n * disconnected and instead separately track \"latest clientId\" in SummaryManager.\n */\n readonly clientId: string | undefined;\n}\n\nexport interface ISummaryManagerEvents extends IEvent {\n (event: \"summarizerWarning\", listener: (warning: ISummarizingWarning) => void);\n}\n\nexport interface ISummaryManagerConfig {\n initialDelayMs: number;\n opsToBypassInitialDelay: 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<ISummaryManagerEvents> implements IDisposable {\n private readonly logger: ITelemetryLogger;\n private readonly opsToBypassInitialDelay: number;\n private readonly initialDelayMs: number;\n private latestClientId: string | undefined;\n private state = SummaryManagerState.Off;\n private summarizer?: ISummarizer;\n private _disposed = false;\n\n public get disposed() {\n return this._disposed;\n }\n\n public get currentState() { return this.state; }\n\n constructor(\n private readonly clientElection: ISummarizerClientElection,\n private readonly connectedState: IConnectedState,\n private readonly summaryCollection:\n Pick<SummaryCollection, \"opsSinceLastAck\" | \"addOpListener\" | \"removeOpListener\">,\n parentLogger: ITelemetryLogger,\n /** Creates summarizer by asking interactive container to spawn summarizing container and\n * get back its Summarizer instance. */\n private readonly requestSummarizerFn: () => Promise<ISummarizer>,\n private readonly startThrottler: IThrottler,\n {\n initialDelayMs = defaultInitialDelayMs,\n opsToBypassInitialDelay = defaultOpsToBypassInitialDelay,\n }: Readonly<Partial<ISummaryManagerConfig>> = {},\n private readonly summarizerOptions?: Readonly<Partial<ISummarizerOptions>>,\n ) {\n super();\n\n this.logger = ChildLogger.create(\n parentLogger,\n \"SummaryManager\",\n {all:{ clientId: () => this.latestClientId }});\n\n this.connectedState.on(\"connected\", this.handleConnected);\n this.connectedState.on(\"disconnected\", this.handleDisconnected);\n this.latestClientId = this.connectedState.clientId;\n\n this.opsToBypassInitialDelay = opsToBypassInitialDelay;\n this.initialDelayMs = initialDelayMs;\n }\n\n /**\n * Until start is called, the SummaryManager won't begin attempting to start summarization. This ensures there's\n * a window between construction and starting where the caller can attach listeners.\n */\n public start(): void {\n this.clientElection.on(\"electedSummarizerChanged\", this.refreshSummarizer);\n this.refreshSummarizer();\n }\n\n private readonly handleConnected = (clientId: string) => {\n this.latestClientId = clientId;\n // If we have a summarizer, it should have been either cancelled on disconnected by now.\n // But because of lastSummary process, it can still hang around, so there is not much we can\n // check or assert.\n this.refreshSummarizer();\n };\n\n private readonly handleDisconnected = () => {\n this.refreshSummarizer();\n };\n\n private static readonly isStartingOrRunning = (state: SummaryManagerState) =>\n state === SummaryManagerState.Starting || state === SummaryManagerState.Running;\n\n private getShouldSummarizeState(): ShouldSummarizeState {\n if (!this.connectedState.connected) {\n return { shouldSummarize: false, stopReason: \"parentNotConnected\" };\n } else if (this.connectedState.clientId !== this.clientElection.electedClientId) {\n return { shouldSummarize: false, stopReason: \"parentShouldNotSummarize\" };\n } else if (this.disposed) {\n assert(false, 0x260 /* \"Disposed should mean disconnected!\" */);\n } else {\n return { shouldSummarize: true };\n }\n }\n\n private readonly refreshSummarizer = () => {\n // Transition states depending on shouldSummarize, which is a calculated property\n // that is only true if this client is connected and is the elected summarizer.\n const shouldSummarizeState = this.getShouldSummarizeState();\n switch (this.state) {\n case SummaryManagerState.Off: {\n if (shouldSummarizeState.shouldSummarize) {\n this.startSummarization();\n }\n return;\n }\n case SummaryManagerState.Starting: {\n // Cannot take any action until summarizer is created\n // state transition will occur after creation\n return;\n }\n case SummaryManagerState.Running: {\n if (shouldSummarizeState.shouldSummarize === false) {\n this.stop(shouldSummarizeState.stopReason);\n }\n return;\n }\n case SummaryManagerState.Stopping: {\n // Cannot take any action until running summarizer finishes\n // state transition will occur after it stops\n return;\n }\n default: {\n return;\n }\n }\n };\n\n private startSummarization() {\n assert(this.state === SummaryManagerState.Off, 0x261 /* \"Expected: off\" */);\n this.state = SummaryManagerState.Starting;\n\n assert(this.summarizer === undefined, 0x262 /* \"Old summarizer is still working!\" */);\n\n let reason = \"unknown\";\n\n this.delayBeforeCreatingSummarizer().then(async (startWithInitialDelay: boolean) => {\n // Re-validate that it need to be running. Due to asynchrony, it may be not the case anymore\n // but only if creation was delayed. If it was not, then we want to ensure we always create\n // a summarizer to kick off lastSummary. Without that, we would not be able to summarize and get\n // document out of broken state if it has too many ops and ordering service keeps nacking main\n // container (and thus it goes into cycle of reconnects)\n if (startWithInitialDelay && this.getShouldSummarizeState().shouldSummarize === false) {\n return;\n }\n\n const summarizer = await this.requestSummarizerFn();\n\n // Re-validate that it need to be running. Due to asynchrony, it may be not the case anymore\n const shouldSummarizeState = this.getShouldSummarizeState();\n if (shouldSummarizeState.shouldSummarize === false) {\n summarizer.stop(shouldSummarizeState.stopReason);\n return;\n }\n\n assert(this.state === SummaryManagerState.Starting, 0x263 /* \"Expected: starting\" */);\n this.state = SummaryManagerState.Running;\n\n summarizer.on(\"summarizingError\",\n (warning: ISummarizingWarning) => this.emit(\"summarizerWarning\", warning));\n this.summarizer = summarizer;\n\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n const clientId = this.latestClientId!;\n\n reason = await PerformanceEvent.timedExecAsync(\n this.logger,\n { eventName: \"RunningSummarizer\", attempt: this.startThrottler.numAttempts },\n async () => summarizer.run(clientId, this.summarizerOptions),\n );\n }).catch((error) => {\n // Most of exceptions happen due to container being closed while loading it, due to\n // summarizer container loosing connection while load.\n // Not worth reporting such errors as errors. That said, we might miss some real errors if\n // we ignore blindly, so try to narrow signature we are looking for - skip logging\n // error only if this client should no longer be a summarizer (which in practice\n // means it also lost connection), and error happened on load (we do not have summarizer).\n // We could add error.fluidErrorCode !== \"containerClosedWithoutErrorDuringLoad\" check to narrow it down,\n // but that does not seem to be necessary.\n if (this.getShouldSummarizeState().shouldSummarize || this.summarizer !== undefined) {\n // Report any failure as an error unless it was due to cancellation (like \"disconnected\" error)\n // If failure happened on container load, we may not yet realized that socket disconnected, so check\n // offlineError.\n const category = error?.errorType === DriverErrorType.offlineError ? \"generic\" : \"error\";\n this.logger.sendTelemetryEvent(\n {\n eventName: \"SummarizerException\",\n category,\n },\n error);\n this.emit(\"summarizerWarning\", error);\n\n // Note that summarizer may keep going (like doing last summary).\n // Ideally we await stopping process, but this code path is due to a bug\n // that needs to be fixed either way.\n if (SummaryManager.isStartingOrRunning(this.state)) {\n this.stop(\"summarizerException\");\n }\n }\n }).finally(() => {\n assert(this.state !== SummaryManagerState.Off, 0x264 /* \"Expected: Not Off\" */);\n this.state = SummaryManagerState.Off;\n\n this.summarizer = undefined;\n\n this.logger.sendTelemetryEvent({\n eventName: \"EndingSummarizer\",\n reason,\n });\n\n if (this.getShouldSummarizeState().shouldSummarize) {\n this.startSummarization();\n }\n });\n }\n\n private stop(reason: SummarizerStopReason) {\n if (!SummaryManager.isStartingOrRunning(this.state)) {\n return;\n }\n this.state = SummaryManagerState.Stopping;\n\n // Stopping the running summarizer client should trigger a change\n // in states when the running summarizer closes\n this.summarizer?.stop(reason);\n }\n\n /**\n * Implements initial delay before creating summarizer\n * @returns true, if creation is delayed due to heuristics (not many ops to summarize).\n * False if summarizer should start immediately due to too many unsummarized ops.\n */\n private async delayBeforeCreatingSummarizer(): Promise<boolean> {\n // throttle creation of new summarizer containers to prevent spamming the server with websocket connections\n let delayMs = this.startThrottler.getDelay();\n if (delayMs > 0 && delayMs > this.startThrottler.maxDelayMs) {\n this.emit(\n \"summarizerWarning\",\n createSummarizingWarning(\"summaryManagerCreateSummarizerMaxThrottleDelay\", false),\n );\n }\n\n // We have been elected the summarizer. Some day we may be able to summarize with a live document but for\n // now we play it safe and launch a second copy.\n this.logger.sendTelemetryEvent({\n eventName: \"CreatingSummarizer\",\n throttlerDelay: delayMs,\n initialDelay: this.initialDelayMs,\n opsSinceLastAck: this.summaryCollection.opsSinceLastAck,\n opsToBypassInitialDelay: this.opsToBypassInitialDelay,\n });\n\n // This delay helps ensure that last summarizer that might be left from previous client\n // has enough time to complete its last summary and thus new summarizer not conflict with previous one.\n // If, however, there are too many unsummarized ops, try to resolve it as quickly as possible, with\n // understanding that we may see nacks because of such quick action.\n // A better design would be for summarizer election logic to always select current summarizer as\n // summarizing client (i.e. clientType === \"summarizer\" can be elected) to ensure that nobody else can\n // summarizer while it finishes its work and moves to exit.\n // It also helps with pure boot scenario (single client) to offset expensive work a bit out from\n // critical boot sequence.\n let startWithInitialDelay = false;\n if (this.summaryCollection.opsSinceLastAck < this.opsToBypassInitialDelay) {\n startWithInitialDelay = true;\n delayMs = Math.max(delayMs, this.initialDelayMs);\n }\n\n if (delayMs > 0) {\n let timer;\n let resolveOpPromiseFn;\n // Create a listener that will break the delay if we've exceeded the initial delay ops count.\n const opsListenerFn = () => {\n if (this.summaryCollection.opsSinceLastAck >= this.opsToBypassInitialDelay) {\n clearTimeout(timer);\n resolveOpPromiseFn();\n }\n };\n // Create a Promise that will resolve when the delay expires.\n const delayPromise = new Promise<void>((resolve) => {\n timer = setTimeout(() => resolve(), delayMs);\n });\n // Create a Promise that will resolve if the ops count passes the threshold.\n const opPromise = new Promise<void>((resolve) => { resolveOpPromiseFn = resolve; });\n this.summaryCollection.addOpListener(opsListenerFn);\n await Promise.race([ delayPromise, opPromise ]);\n this.summaryCollection.removeOpListener(opsListenerFn);\n }\n return startWithInitialDelay;\n }\n\n public readonly summarizeOnDemand: ISummarizer[\"summarizeOnDemand\"] = (...args) => {\n if (this.summarizer === undefined) {\n throw Error(\"No running summarizer client\");\n // TODO: could spawn a summarizer client temporarily.\n }\n return this.summarizer.summarizeOnDemand(...args);\n };\n\n public readonly enqueueSummarize: ISummarizer[\"enqueueSummarize\"] = (...args) => {\n if (this.summarizer === undefined) {\n throw Error(\"No running summarizer client\");\n // TODO: could spawn a summarizer client temporarily.\n }\n return this.summarizer.enqueueSummarize(...args);\n };\n\n public dispose() {\n this.clientElection.off(\"electedSummarizerChanged\", this.refreshSummarizer);\n this.connectedState.off(\"connected\", this.handleConnected);\n this.connectedState.off(\"disconnected\", this.handleDisconnected);\n this._disposed = true;\n }\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fluidframework/container-runtime",
3
- "version": "0.54.2",
3
+ "version": "0.56.0-49831",
4
4
  "description": "Fluid container runtime",
5
5
  "homepage": "https://fluidframework.com",
6
6
  "repository": "https://github.com/microsoft/FluidFramework",
@@ -23,7 +23,7 @@
23
23
  "ci:build:docs": "api-extractor run --typescript-compiler-folder ../../../node_modules/typescript && copyfiles -u 1 ./_api-extractor-temp/doc-models/* ../../../_api-extractor-temp/",
24
24
  "clean": "rimraf dist lib *.tsbuildinfo *.build.log",
25
25
  "eslint": "eslint --format stylish src",
26
- "eslint:fix": "eslint --format stylish src --fix",
26
+ "eslint:fix": "eslint --format stylish src --fix --fix-type problem,suggestion,layout",
27
27
  "lint": "npm run eslint",
28
28
  "lint:fix": "npm run eslint:fix",
29
29
  "test": "npm run test:mocha",
@@ -58,45 +58,46 @@
58
58
  "dependencies": {
59
59
  "@fluidframework/common-definitions": "^0.20.1",
60
60
  "@fluidframework/common-utils": "^0.32.1",
61
- "@fluidframework/container-definitions": "^0.44.0",
62
- "@fluidframework/container-runtime-definitions": "^0.54.2",
63
- "@fluidframework/container-utils": "^0.54.2",
64
- "@fluidframework/core-interfaces": "^0.41.0",
65
- "@fluidframework/datastore": "^0.54.2",
66
- "@fluidframework/driver-definitions": "^0.43.0",
67
- "@fluidframework/driver-utils": "^0.54.2",
68
- "@fluidframework/garbage-collector": "^0.54.2",
61
+ "@fluidframework/container-definitions": "^0.45.0-0",
62
+ "@fluidframework/container-runtime-definitions": "0.56.0-49831",
63
+ "@fluidframework/container-utils": "0.56.0-49831",
64
+ "@fluidframework/core-interfaces": "^0.42.0-0",
65
+ "@fluidframework/datastore": "0.56.0-49831",
66
+ "@fluidframework/driver-definitions": "^0.44.0-0",
67
+ "@fluidframework/driver-utils": "0.56.0-49831",
68
+ "@fluidframework/garbage-collector": "0.56.0-49831",
69
69
  "@fluidframework/protocol-base": "^0.1034.0",
70
70
  "@fluidframework/protocol-definitions": "^0.1026.0",
71
- "@fluidframework/runtime-definitions": "^0.54.2",
72
- "@fluidframework/runtime-utils": "^0.54.2",
73
- "@fluidframework/telemetry-utils": "^0.54.2",
71
+ "@fluidframework/runtime-definitions": "0.56.0-49831",
72
+ "@fluidframework/runtime-utils": "0.56.0-49831",
73
+ "@fluidframework/telemetry-utils": "0.56.0-49831",
74
74
  "double-ended-queue": "^2.1.0-0",
75
75
  "uuid": "^8.3.1"
76
76
  },
77
77
  "devDependencies": {
78
78
  "@fluidframework/build-common": "^0.23.0",
79
- "@fluidframework/eslint-config-fluid": "^0.24.0",
80
- "@fluidframework/mocha-test-setup": "^0.54.2",
81
- "@fluidframework/test-runtime-utils": "^0.54.2",
79
+ "@fluidframework/eslint-config-fluid": "^0.25.0",
80
+ "@fluidframework/mocha-test-setup": "0.56.0-49831",
81
+ "@fluidframework/test-runtime-utils": "0.56.0-49831",
82
82
  "@microsoft/api-extractor": "^7.16.1",
83
+ "@rushstack/eslint-config": "^2.5.1",
83
84
  "@types/double-ended-queue": "^2.1.0",
84
85
  "@types/mocha": "^8.2.2",
85
86
  "@types/node": "^14.18.0",
86
87
  "@types/sinon": "^7.0.13",
87
88
  "@types/uuid": "^8.3.0",
88
- "@typescript-eslint/eslint-plugin": "~4.14.0",
89
- "@typescript-eslint/parser": "~4.14.0",
89
+ "@typescript-eslint/eslint-plugin": "~5.9.0",
90
+ "@typescript-eslint/parser": "~5.9.0",
90
91
  "concurrently": "^6.2.0",
91
92
  "copyfiles": "^2.1.0",
92
93
  "cross-env": "^7.0.2",
93
- "eslint": "~7.18.0",
94
+ "eslint": "~8.6.0",
95
+ "eslint-plugin-editorconfig": "~3.2.0",
94
96
  "eslint-plugin-eslint-comments": "~3.2.0",
95
- "eslint-plugin-import": "~2.22.1",
97
+ "eslint-plugin-import": "~2.25.4",
96
98
  "eslint-plugin-no-null": "~1.0.2",
97
- "eslint-plugin-prefer-arrow": "~1.2.2",
98
- "eslint-plugin-react": "~7.22.0",
99
- "eslint-plugin-unicorn": "~26.0.1",
99
+ "eslint-plugin-react": "~7.28.0",
100
+ "eslint-plugin-unicorn": "~40.0.0",
100
101
  "mocha": "^8.4.0",
101
102
  "nyc": "^15.0.0",
102
103
  "rimraf": "^2.6.2",
@@ -104,7 +104,7 @@ export class BlobManager {
104
104
  if (this.runtime.attachState === AttachState.Attaching) {
105
105
  // blob upload is not supported in "Attaching" state
106
106
  this.logger.sendTelemetryEvent({ eventName: "CreateBlobWhileAttaching" });
107
- await new Promise<void>((res) => this.runtime.once("attached", res));
107
+ await new Promise<void>((resolve) => this.runtime.once("attached", resolve));
108
108
  }
109
109
 
110
110
  const response = await this.getStorage().createBlob(blob);
@@ -4,10 +4,9 @@
4
4
  */
5
5
 
6
6
  import { EventEmitter } from "events";
7
- import { ITelemetryGenericEvent, ITelemetryLogger } from "@fluidframework/common-definitions";
7
+ import { ITelemetryBaseLogger, ITelemetryGenericEvent, ITelemetryLogger } from "@fluidframework/common-definitions";
8
8
  import {
9
9
  FluidObject,
10
- IFluidConfiguration,
11
10
  IFluidHandle,
12
11
  IFluidHandleContext,
13
12
  IFluidObject,
@@ -51,7 +50,6 @@ import {
51
50
  import { DriverHeader, IDocumentStorageService, ISummaryContext } from "@fluidframework/driver-definitions";
52
51
  import { readAndParse, BlobAggregationStorage } from "@fluidframework/driver-utils";
53
52
  import {
54
- CreateProcessingError,
55
53
  DataCorruptionError,
56
54
  GenericError,
57
55
  UsageError,
@@ -77,7 +75,7 @@ import {
77
75
  IFluidDataStoreRegistry,
78
76
  IFluidDataStoreChannel,
79
77
  IGarbageCollectionData,
80
- IGarbageCollectionSummaryDetails,
78
+ IGarbageCollectionDetailsBase,
81
79
  IEnvelope,
82
80
  IInboundSignalMessage,
83
81
  ISignalEnvelope,
@@ -291,22 +289,34 @@ type IRuntimeMessageMetadata = undefined | {
291
289
  batch?: boolean;
292
290
  };
293
291
 
292
+ /**
293
+ * @deprecated
294
+ * Untagged logger is unsupported going forward. There are old loaders with old ContainerContexts that only
295
+ * have the untagged logger, so to accommodate that scenario the below interface is used. It can be removed once
296
+ * its usage is removed from TaggedLoggerAdapter fallback.
297
+ */
298
+ interface OldContainerContextWithLogger extends IContainerContext {
299
+ logger: ITelemetryBaseLogger;
300
+ };
301
+
294
302
  // Local storage key to set the default flush mode to TurnBased
295
303
  const turnBasedFlushModeKey = "Fluid.ContainerRuntime.FlushModeTurnBased";
296
304
 
305
+ export enum RuntimeMessage {
306
+ FluidDataStoreOp = "component",
307
+ Attach = "attach",
308
+ ChunkedOp = "chunkedOp",
309
+ BlobAttach = "blobAttach",
310
+ Rejoin = "rejoin",
311
+ Alias = "alias",
312
+ Operation = "op",
313
+ }
314
+
297
315
  export function isRuntimeMessage(message: ISequencedDocumentMessage): boolean {
298
- switch (message.type) {
299
- case ContainerMessageType.FluidDataStoreOp:
300
- case ContainerMessageType.ChunkedOp:
301
- case ContainerMessageType.Attach:
302
- case ContainerMessageType.Alias:
303
- case ContainerMessageType.BlobAttach:
304
- case ContainerMessageType.Rejoin:
305
- case MessageType.Operation:
306
- return true;
307
- default:
308
- return false;
316
+ if ((Object.values(RuntimeMessage) as string[]).includes(message.type)) {
317
+ return true;
309
318
  }
319
+ return false;
310
320
  }
311
321
 
312
322
  export function unpackRuntimeMessage(message: ISequencedDocumentMessage) {
@@ -608,6 +618,7 @@ export function getDeviceSpec() {
608
618
  }
609
619
  return {};
610
620
  }
621
+
611
622
  /**
612
623
  * Represents the runtime of the container. Contains helper functions/state of the container.
613
624
  * It will define the store level mappings.
@@ -640,7 +651,9 @@ export class ContainerRuntime extends TypedEventEmitter<IContainerRuntimeEvents>
640
651
  existing?: boolean,
641
652
  ): Promise<ContainerRuntime> {
642
653
  // If taggedLogger exists, use it. Otherwise, wrap the vanilla logger:
643
- const passLogger = context.taggedLogger ?? new TaggedLoggerAdapter(context.logger);
654
+ // back-compat: Remove the TaggedLoggerAdapter fallback once all the host are using loader > 0.45
655
+ const passLogger = context.taggedLogger ?? new TaggedLoggerAdapter((context as
656
+ OldContainerContextWithLogger).logger);
644
657
  const logger = ChildLogger.create(passLogger, undefined, {
645
658
  all: {
646
659
  runtimeVersion: pkgVersion,
@@ -756,13 +769,6 @@ export class ContainerRuntime extends TypedEventEmitter<IContainerRuntimeEvents>
756
769
  return runtime;
757
770
  }
758
771
 
759
- /**
760
- * @deprecated This will be removed in a later release. Deprecated in 0.53
761
- */
762
- public get id(): string {
763
- return this.context.id;
764
- }
765
-
766
772
  public get options(): ILoaderOptions {
767
773
  return this.context.options;
768
774
  }
@@ -883,6 +889,9 @@ export class ContainerRuntime extends TypedEventEmitter<IContainerRuntimeEvents>
883
889
 
884
890
  private dirtyContainer = false;
885
891
  private emitDirtyDocumentEvent = true;
892
+
893
+ private summarizerWarning = (warning: ContainerWarning) =>
894
+ this.mc.logger.sendTelemetryEvent({ eventName: "summarizerWarning" }, warning);
886
895
  /**
887
896
  * Summarizer is responsible for coordinating when to send generate and send summaries.
888
897
  * It is the main entry point for summary work.
@@ -900,14 +909,6 @@ export class ContainerRuntime extends TypedEventEmitter<IContainerRuntimeEvents>
900
909
 
901
910
  private readonly dataStores: DataStores;
902
911
 
903
- /**
904
- * True, if GC data should be written at root of the summary tree.
905
- * False, if data stores should write GC blobs in their summary tree.
906
- */
907
- public get writeGCDataAtRoot(): boolean {
908
- return this.garbageCollector.writeDataAtRoot;
909
- }
910
-
911
912
  /**
912
913
  * True if generating summaries with isolated channels is
913
914
  * explicitly disabled. This only affects how summaries are written,
@@ -995,6 +996,7 @@ export class ContainerRuntime extends TypedEventEmitter<IContainerRuntimeEvents>
995
996
  this.runtimeOptions.gcOptions,
996
997
  (unusedRoutes: string[]) => this.dataStores.deleteUnusedRoutes(unusedRoutes),
997
998
  getCurrentTimestamp,
999
+ this.closeFn,
998
1000
  context.baseSnapshot,
999
1001
  async <T>(id: string) => readAndParse<T>(this.storage, id),
1000
1002
  this.mc.logger,
@@ -1034,20 +1036,21 @@ export class ContainerRuntime extends TypedEventEmitter<IContainerRuntimeEvents>
1034
1036
  (id: string, createParam: CreateChildSummarizerNodeParam) => (
1035
1037
  summarizeInternal: SummarizeInternalFn,
1036
1038
  getGCDataFn: (fullGC?: boolean) => Promise<IGarbageCollectionData>,
1037
- getInitialGCSummaryDetailsFn: () => Promise<IGarbageCollectionSummaryDetails>,
1039
+ getBaseGCDetailsFn: () => Promise<IGarbageCollectionDetailsBase>,
1038
1040
  ) => this.summarizerNode.createChild(
1039
1041
  summarizeInternal,
1040
1042
  id,
1041
1043
  createParam,
1042
1044
  undefined,
1043
1045
  getGCDataFn,
1044
- getInitialGCSummaryDetailsFn,
1046
+ getBaseGCDetailsFn,
1045
1047
  ),
1046
1048
  (id: string) => this.summarizerNode.deleteChild(id),
1047
1049
  this.mc.logger,
1048
1050
  async () => this.garbageCollector.getDataStoreBaseGCDetails(),
1049
1051
  (id: string) => this.garbageCollector.nodeChanged(id),
1050
1052
  new Map<string, string>(dataStoreAliasMap),
1053
+ this.garbageCollector.writeDataAtRoot,
1051
1054
  );
1052
1055
 
1053
1056
  this.blobManager = new BlobManager(
@@ -1162,7 +1165,7 @@ export class ContainerRuntime extends TypedEventEmitter<IContainerRuntimeEvents>
1162
1165
  },
1163
1166
  this.runtimeOptions.summaryOptions.summarizerOptions,
1164
1167
  );
1165
- this.summaryManager.on("summarizerWarning", this.raiseContainerWarning);
1168
+ this.summaryManager.on("summarizerWarning", this.summarizerWarning);
1166
1169
  this.summaryManager.start();
1167
1170
  }
1168
1171
  }
@@ -1228,13 +1231,13 @@ export class ContainerRuntime extends TypedEventEmitter<IContainerRuntimeEvents>
1228
1231
  }, error);
1229
1232
 
1230
1233
  if (this.summaryManager !== undefined) {
1231
- this.summaryManager.off("summarizerWarning", this.raiseContainerWarning);
1234
+ this.summaryManager.off("summarizerWarning", this.summarizerWarning);
1232
1235
  this.summaryManager.dispose();
1233
1236
  }
1237
+ this.garbageCollector.dispose();
1234
1238
  this._summarizer?.dispose();
1235
1239
  this.dataStores.dispose();
1236
1240
  this.pendingStateManager.dispose();
1237
-
1238
1241
  this.emit("dispose");
1239
1242
  this.removeAllListeners();
1240
1243
  }
@@ -1249,10 +1252,6 @@ export class ContainerRuntime extends TypedEventEmitter<IContainerRuntimeEvents>
1249
1252
  return undefined;
1250
1253
  }
1251
1254
 
1252
- public get IFluidConfiguration(): IFluidConfiguration {
1253
- return this.context.configuration;
1254
- }
1255
-
1256
1255
  /**
1257
1256
  * Notifies this object about the request made to the container.
1258
1257
  * @param request - Request made to the handler.
@@ -1343,6 +1342,7 @@ export class ContainerRuntime extends TypedEventEmitter<IContainerRuntimeEvents>
1343
1342
  // The last message processed at the time of summary. If there are no messages, nothing has changed from
1344
1343
  // the base summary we loaded from. So, use the message from its metadata blob.
1345
1344
  message: extractSummaryMetadataMessage(this.deltaManager.lastMessage) ?? this.baseSummaryMessage,
1345
+ sessionExpiryTimeoutMs: this.garbageCollector.sessionExpiryTimeoutMs,
1346
1346
  };
1347
1347
  }
1348
1348
 
@@ -1358,7 +1358,7 @@ export class ContainerRuntime extends TypedEventEmitter<IContainerRuntimeEvents>
1358
1358
  const dataStoreContext = await this.dataStores.getDataStore(id, wait);
1359
1359
  // The data store is referenced if used routes in the initial summary has a route to self.
1360
1360
  // Older documents may not have used routes in the summary. They are considered referenced.
1361
- const usedRoutes = (await dataStoreContext.getInitialGCSummaryDetails()).usedRoutes;
1361
+ const usedRoutes = (await dataStoreContext.getBaseGCDetails()).usedRoutes;
1362
1362
  if (usedRoutes === undefined || usedRoutes.includes("") || usedRoutes.includes("/")) {
1363
1363
  return dataStoreContext.realize();
1364
1364
  }
@@ -1383,7 +1383,7 @@ export class ContainerRuntime extends TypedEventEmitter<IContainerRuntimeEvents>
1383
1383
  return convertSummaryTreeToITree(summaryResult.summary);
1384
1384
  }
1385
1385
 
1386
- private addContainerBlobsToSummary(summaryTree: ISummaryTreeWithStats) {
1386
+ private addContainerStateToSummary(summaryTree: ISummaryTreeWithStats) {
1387
1387
  addBlobToSummary(summaryTree, metadataBlobName, JSON.stringify(this.formMetadata()));
1388
1388
  if (this.chunkMap.size > 0) {
1389
1389
  const content = JSON.stringify([...this.chunkMap]);
@@ -1408,7 +1408,7 @@ export class ContainerRuntime extends TypedEventEmitter<IContainerRuntimeEvents>
1408
1408
  addTreeToSummary(summaryTree, blobsTreeName, blobsTree);
1409
1409
  }
1410
1410
 
1411
- if (this.writeGCDataAtRoot) {
1411
+ if (this.garbageCollector.writeDataAtRoot) {
1412
1412
  const gcSummary = this.garbageCollector.summarize();
1413
1413
  if (gcSummary !== undefined) {
1414
1414
  addTreeToSummary(summaryTree, gcTreeKey, gcSummary);
@@ -1660,20 +1660,18 @@ export class ContainerRuntime extends TypedEventEmitter<IContainerRuntimeEvents>
1660
1660
  const savedFlushMode = this.flushMode;
1661
1661
  this.setFlushMode(FlushMode.TurnBased);
1662
1662
 
1663
- try {
1664
- this.trackOrderSequentiallyCalls(callback);
1665
- this.flush();
1666
- this.setFlushMode(savedFlushMode);
1667
- } catch(error) {
1668
- this.closeFn(CreateProcessingError(error, "orderSequentially"));
1669
- throw error; // throw the original error for the consumer of the runtime
1670
- }
1663
+ this.trackOrderSequentiallyCalls(callback);
1664
+ this.flush();
1665
+ this.setFlushMode(savedFlushMode);
1671
1666
  }
1672
1667
 
1673
1668
  private trackOrderSequentiallyCalls(callback: () => void): void {
1674
1669
  try {
1675
1670
  this._orderSequentiallyCalls++;
1676
1671
  callback();
1672
+ } catch (error) {
1673
+ this.closeFn(new GenericError("orderSequentiallyCallbackException", error));
1674
+ throw error; // throw the original error for the consumer of the runtime
1677
1675
  } finally {
1678
1676
  this._orderSequentiallyCalls--;
1679
1677
  }
@@ -1723,7 +1721,7 @@ export class ContainerRuntime extends TypedEventEmitter<IContainerRuntimeEvents>
1723
1721
  }
1724
1722
 
1725
1723
  private canSendOps() {
1726
- return this.connected && !this.deltaManager.readonly;
1724
+ return this.connected && !this.deltaManager.readOnlyInfo.readonly;
1727
1725
  }
1728
1726
 
1729
1727
  public getQuorum(): IQuorumClients {
@@ -1735,11 +1733,6 @@ export class ContainerRuntime extends TypedEventEmitter<IContainerRuntimeEvents>
1735
1733
  return this.context.audience!;
1736
1734
  }
1737
1735
 
1738
- // @deprecated Needs to become private
1739
- public readonly raiseContainerWarning = (warning: ContainerWarning) => {
1740
- this.context.raiseContainerWarning(warning);
1741
- };
1742
-
1743
1736
  /**
1744
1737
  * Returns true of container is dirty, i.e. there are some pending local changes that
1745
1738
  * either were not sent out to delta stream or were not yet acknowledged.
@@ -1810,7 +1803,7 @@ export class ContainerRuntime extends TypedEventEmitter<IContainerRuntimeEvents>
1810
1803
  // Wrap data store summaries in .channels subtree.
1811
1804
  wrapSummaryInChannelsTree(summarizeResult);
1812
1805
  }
1813
- this.addContainerBlobsToSummary(summarizeResult);
1806
+ this.addContainerStateToSummary(summarizeResult);
1814
1807
  return summarizeResult.summary;
1815
1808
  }
1816
1809
 
@@ -1833,7 +1826,7 @@ export class ContainerRuntime extends TypedEventEmitter<IContainerRuntimeEvents>
1833
1826
  wrapSummaryInChannelsTree(summarizeResult);
1834
1827
  pathPartsForChildren = [channelsTreeName];
1835
1828
  }
1836
- this.addContainerBlobsToSummary(summarizeResult);
1829
+ this.addContainerStateToSummary(summarizeResult);
1837
1830
  return {
1838
1831
  ...summarizeResult,
1839
1832
  id: "",
@@ -1858,6 +1851,8 @@ export class ContainerRuntime extends TypedEventEmitter<IContainerRuntimeEvents>
1858
1851
  /** True to run GC sweep phase after the mark phase */
1859
1852
  runSweep?: boolean,
1860
1853
  }): Promise<ISummaryTreeWithStats> {
1854
+ this.verifyNotClosed();
1855
+
1861
1856
  const { summaryLogger, fullTree = false, trackState = true, runGC = true, runSweep, fullGC } = options;
1862
1857
 
1863
1858
  if (runGC) {
@@ -1871,6 +1866,16 @@ export class ContainerRuntime extends TypedEventEmitter<IContainerRuntimeEvents>
1871
1866
  return summarizeResult as ISummaryTreeWithStats;
1872
1867
  }
1873
1868
 
1869
+ /**
1870
+ * Implementation of IGarbageCollectionRuntime::updateStateBeforeGC.
1871
+ * Before GC runs, called by the garbage collector to update any pending GC state. This is mainly used to notify
1872
+ * the garbage collector of references detected since the last GC run. Most references are notified immediately
1873
+ * but there can be some for which async operation is required (such as detecting new root data stores).
1874
+ */
1875
+ public async updateStateBeforeGC() {
1876
+ return this.dataStores.updateStateBeforeGC();
1877
+ }
1878
+
1874
1879
  /**
1875
1880
  * Implementation of IGarbageCollectionRuntime::getGCData.
1876
1881
  * Generates and returns the GC data for this container.
@@ -2008,10 +2013,9 @@ export class ContainerRuntime extends TypedEventEmitter<IContainerRuntimeEvents>
2008
2013
  try {
2009
2014
  summarizeResult = await this.summarize({
2010
2015
  summaryLogger,
2011
- // If the GC version changed since the last summary was submitted, we need to regenerate summary by
2012
- // running full summary. This is used to handle scenarios where we upgrade the GC version because we
2013
- // cannot trust the data from the previous GC version anymore.
2014
- fullTree: fullTree || this.garbageCollector.hasGCVersionChanged,
2016
+ // If the GC state needs to be reset, we need to regenerate the summary and update the unreferenced
2017
+ // state of all the nodes.
2018
+ fullTree: fullTree || this.garbageCollector.summaryStateNeedsReset,
2015
2019
  trackState: true,
2016
2020
  runGC: this.garbageCollector.shouldRunGC,
2017
2021
  });
@@ -2488,13 +2492,13 @@ export class ContainerRuntime extends TypedEventEmitter<IContainerRuntimeEvents>
2488
2492
  const waitForSeq = async (
2489
2493
  deltaManager: IDeltaManager<Pick<ISequencedDocumentMessage, "sequenceNumber">, unknown>,
2490
2494
  targetSeq: number,
2491
- ): Promise<void> => new Promise<void>((accept, reject) => {
2495
+ ): Promise<void> => new Promise<void>((resolve, reject) => {
2492
2496
  // TODO: remove cast to any when actual event is determined
2493
2497
  deltaManager.on("closed" as any, reject);
2494
2498
 
2495
2499
  const handleOp = (message: Pick<ISequencedDocumentMessage, "sequenceNumber">) => {
2496
2500
  if (message.sequenceNumber >= targetSeq) {
2497
- accept();
2501
+ resolve();
2498
2502
  deltaManager.off("op", handleOp);
2499
2503
  }
2500
2504
  };