From dc48446d7c4914aca2a76095205975824aac1ba5 Mon Sep 17 00:00:00 2001 From: Mark Fields Date: Mon, 16 Dec 2024 15:59:53 -0800 Subject: [PATCH] Deprecate ContainerRuntime class (#23331) Precursor to #23329. We intend to mark the class `ContainerRuntime` as `@internal` which will give us great freedom to iterate on its internals freely - it is an implementation detail after all! To do so we need to put it on a deprecation path so any few remaining usages in partner code are migrated off `ContainerRuntime`, like so: * When using it as a type, replace it with an interface like `IContainerRuntime` (or in rare cases, `IRuntime`) * When using the static function `ContainerRuntime.loadRuntime` replace it with the free function `loadContainerRuntime`. --------- Co-authored-by: Alex Villarreal <716334+alexvy86@users.noreply.github.com> Co-authored-by: Joshua Smithrud <54606601+Josmithr@users.noreply.github.com> --- .changeset/plain-mails-tan.md | 24 +++++++++++++++++++ ...lContainerRuntimeFactoryWithAttribution.ts | 7 ++---- .../compositeRuntime/loadCompositeRuntime.ts | 4 ++-- .../api-report/aqueduct.legacy.alpha.api.md | 8 +++---- .../baseContainerRuntimeFactory.ts | 24 +++++++++++++++++-- .../attributor/src/mixinAttributor.ts | 7 ++++++ .../container-runtime.legacy.alpha.api.md | 2 +- .../container-runtime/src/containerRuntime.ts | 4 ++++ .../runtime-utils.legacy.alpha.api.md | 4 ---- .../runtime-utils/src/runtimeFactoryHelper.ts | 19 +++++++++++++++ .../src/loadTestDataStore.ts | 2 ++ .../src/testContainerRuntimeFactory.ts | 7 ++++++ 12 files changed, 93 insertions(+), 19 deletions(-) create mode 100644 .changeset/plain-mails-tan.md diff --git a/.changeset/plain-mails-tan.md b/.changeset/plain-mails-tan.md new file mode 100644 index 000000000000..146d2f92f297 --- /dev/null +++ b/.changeset/plain-mails-tan.md @@ -0,0 +1,24 @@ +--- +"@fluidframework/aqueduct": minor +"@fluidframework/container-runtime": minor +--- +--- +"section": deprecation +--- + +The ContainerRuntime class is now deprecated + +The class `ContainerRuntime` is deprecated and will no longer be exported starting in version 2.20.0. + +There are two possible migration paths to stop using `ContainerRuntime`: + +* When using it as a type, replace it with an interface like `IContainerRuntime` +* When using the static function `ContainerRuntime.loadRuntime` replace it with the free function `loadContainerRuntime`. + +`BaseContainerRuntimeFactory` has some changes as well, since it exposed `ContainerRuntime` in several function signatures: + +* `instantiateFirstTime` - Takes the wider type `IContainerRuntime` instead of `ContainerRuntime` +* `instantiateFromExisting` - Takes the wider type `IContainerRuntime` instead of `ContainerRuntime` +* `preInitialize` - deprecated as well, since it returns `ContainerRuntime` + +These functions should never be called directly anyway - use `BaseContainerRuntimeFactory.instantiateRuntime` instead. diff --git a/examples/apps/attributable-map/src/modelContainerRuntimeFactoryWithAttribution.ts b/examples/apps/attributable-map/src/modelContainerRuntimeFactoryWithAttribution.ts index 841f8ef247ce..1879ea2fe965 100644 --- a/examples/apps/attributable-map/src/modelContainerRuntimeFactoryWithAttribution.ts +++ b/examples/apps/attributable-map/src/modelContainerRuntimeFactoryWithAttribution.ts @@ -11,14 +11,11 @@ import { IRuntime, IRuntimeFactory, } from "@fluidframework/container-definitions/internal"; -import { - ContainerRuntime, - IContainerRuntimeOptions, -} from "@fluidframework/container-runtime/internal"; +import { IContainerRuntimeOptions } from "@fluidframework/container-runtime/internal"; import { IContainerRuntime } from "@fluidframework/container-runtime-definitions/internal"; import { NamedFluidDataStoreRegistryEntries } from "@fluidframework/runtime-definitions/internal"; -const containerRuntimeWithAttribution = mixinAttributor(ContainerRuntime); +const containerRuntimeWithAttribution = mixinAttributor(); /** * ModelContainerRuntimeFactoryWithAttribution is an abstract class that gives a basic structure for container runtime initialization with attributor enabled. diff --git a/examples/utils/migration-tools/src/compositeRuntime/loadCompositeRuntime.ts b/examples/utils/migration-tools/src/compositeRuntime/loadCompositeRuntime.ts index e80796fc8c37..6974078c6a4b 100644 --- a/examples/utils/migration-tools/src/compositeRuntime/loadCompositeRuntime.ts +++ b/examples/utils/migration-tools/src/compositeRuntime/loadCompositeRuntime.ts @@ -5,8 +5,8 @@ import { IContainerContext, IRuntime } from "@fluidframework/container-definitions/internal"; import { - ContainerRuntime, IContainerRuntimeOptions, + loadContainerRuntime, } from "@fluidframework/container-runtime/internal"; import { IContainerRuntime } from "@fluidframework/container-runtime-definitions/internal"; import type { FluidObject } from "@fluidframework/core-interfaces"; @@ -89,7 +89,7 @@ export const loadCompositeRuntime = async ( compositeEntryPoint: CompositeEntryPoint, runtimeOptions?: IContainerRuntimeOptions, ): Promise => { - const runtime = await ContainerRuntime.loadRuntime({ + const runtime = await loadContainerRuntime({ context, registryEntries: compositeEntryPoint.registryEntries, provideEntryPoint: compositeEntryPoint.provideEntryPoint, diff --git a/packages/framework/aqueduct/api-report/aqueduct.legacy.alpha.api.md b/packages/framework/aqueduct/api-report/aqueduct.legacy.alpha.api.md index 5f29c452b59b..ab51b0de266b 100644 --- a/packages/framework/aqueduct/api-report/aqueduct.legacy.alpha.api.md +++ b/packages/framework/aqueduct/api-report/aqueduct.legacy.alpha.api.md @@ -10,11 +10,9 @@ export class BaseContainerRuntimeFactory extends RuntimeFactoryHelper implements protected containerHasInitialized(runtime: IContainerRuntime): Promise; protected containerInitializingFirstTime(runtime: IContainerRuntime): Promise; get IFluidDataStoreRegistry(): IFluidDataStoreRegistry; - // (undocumented) - instantiateFirstTime(runtime: ContainerRuntime): Promise; - // (undocumented) - instantiateFromExisting(runtime: ContainerRuntime): Promise; - // (undocumented) + instantiateFirstTime(runtime: IContainerRuntime): Promise; + instantiateFromExisting(runtime: IContainerRuntime): Promise; + // @deprecated preInitialize(context: IContainerContext, existing: boolean): Promise; } diff --git a/packages/framework/aqueduct/src/container-runtime-factories/baseContainerRuntimeFactory.ts b/packages/framework/aqueduct/src/container-runtime-factories/baseContainerRuntimeFactory.ts index 584e89ee50d1..7bbe7e050a2e 100644 --- a/packages/framework/aqueduct/src/container-runtime-factories/baseContainerRuntimeFactory.ts +++ b/packages/framework/aqueduct/src/container-runtime-factories/baseContainerRuntimeFactory.ts @@ -5,6 +5,7 @@ import type { IContainerContext } from "@fluidframework/container-definitions/internal"; import { + // eslint-disable-next-line import/no-deprecated -- ContainerRuntime class to be moved to internal scope ContainerRuntime, FluidDataStoreRegistry, type IContainerRuntimeOptions, @@ -97,18 +98,36 @@ export class BaseContainerRuntimeFactory this.registry = new FluidDataStoreRegistry(this.registryEntries); } - public async instantiateFirstTime(runtime: ContainerRuntime): Promise { + /** + * Called the one time the container is created, and not on any subsequent load. + * i.e. only when it's initialized on the client that first created it + * @param runtime - The runtime for the container being initialized + */ + public async instantiateFirstTime(runtime: IContainerRuntime): Promise { await this.containerInitializingFirstTime(runtime); await this.containerHasInitialized(runtime); } - public async instantiateFromExisting(runtime: ContainerRuntime): Promise { + /** + * Called every time the container runtime is loaded for an existing container. + * i.e. every time it's initialized _except_ for when it is first created + * @param runtime - The runtime for the container being initialized + */ + public async instantiateFromExisting(runtime: IContainerRuntime): Promise { await this.containerHasInitialized(runtime); } + /** + * Called at the start of initializing a container, to create the container runtime instance. + * @param context - The context for the container being initialized + * @param existing - Whether the container already exists and is being loaded (else it's being created new just now) + * + * @deprecated This function should not be called directly, use instantiateRuntime instead. + */ public async preInitialize( context: IContainerContext, existing: boolean, + // eslint-disable-next-line import/no-deprecated -- ContainerRuntime class to be moved to internal scope ): Promise { const scope: Partial = context.scope; if (this.dependencyContainer) { @@ -119,6 +138,7 @@ export class BaseContainerRuntimeFactory scope.IFluidDependencySynthesizer = dc; } + // eslint-disable-next-line import/no-deprecated -- ContainerRuntime class to be moved to internal scope return ContainerRuntime.loadRuntime({ context, existing, diff --git a/packages/framework/attributor/src/mixinAttributor.ts b/packages/framework/attributor/src/mixinAttributor.ts index 69e7583e63c0..ec421f21a01e 100644 --- a/packages/framework/attributor/src/mixinAttributor.ts +++ b/packages/framework/attributor/src/mixinAttributor.ts @@ -4,6 +4,7 @@ */ import { type IContainerContext } from "@fluidframework/container-definitions/internal"; +// eslint-disable-next-line import/no-deprecated -- ContainerRuntime class to be moved to internal scope import { ContainerRuntime } from "@fluidframework/container-runtime/internal"; import type { IContainerRuntimeOptions } from "@fluidframework/container-runtime/internal"; import { type IContainerRuntime } from "@fluidframework/container-runtime-definitions/internal"; @@ -52,7 +53,9 @@ export async function getRuntimeAttributor( * @internal */ export const mixinAttributor = ( + // eslint-disable-next-line import/no-deprecated -- ContainerRuntime class to be moved to internal scope Base: typeof ContainerRuntime = ContainerRuntime, + // eslint-disable-next-line import/no-deprecated -- ContainerRuntime class to be moved to internal scope ): typeof ContainerRuntime => class ContainerRuntimeWithAttributor extends Base { public static async loadRuntime(params: { @@ -61,12 +64,14 @@ export const mixinAttributor = ( existing: boolean; runtimeOptions?: IContainerRuntimeOptions; containerScope?: FluidObject; + // eslint-disable-next-line import/no-deprecated -- ContainerRuntime class to be moved to internal scope containerRuntimeCtor?: typeof ContainerRuntime; /** * @deprecated Will be removed once Loader LTS version is "2.0.0-internal.7.0.0". Migrate all usage of IFluidRouter to the "entryPoint" pattern. Refer to Removing-IFluidRouter.md */ requestHandler?: (request: IRequest, runtime: IContainerRuntime) => Promise; provideEntryPoint: (containerRuntime: IContainerRuntime) => Promise; + // eslint-disable-next-line import/no-deprecated -- ContainerRuntime class to be moved to internal scope }): Promise { const { context, @@ -76,6 +81,7 @@ export const mixinAttributor = ( provideEntryPoint, runtimeOptions, containerScope, + // eslint-disable-next-line import/no-deprecated -- ContainerRuntime class to be moved to internal scope containerRuntimeCtor = ContainerRuntimeWithAttributor as unknown as typeof ContainerRuntime, } = params; @@ -123,4 +129,5 @@ export const mixinAttributor = ( return runtime; } + // eslint-disable-next-line import/no-deprecated -- ContainerRuntime class to be moved to internal scope } as unknown as typeof ContainerRuntime; diff --git a/packages/runtime/container-runtime/api-report/container-runtime.legacy.alpha.api.md b/packages/runtime/container-runtime/api-report/container-runtime.legacy.alpha.api.md index 4036d7fe5f8e..4ef75e70cce8 100644 --- a/packages/runtime/container-runtime/api-report/container-runtime.legacy.alpha.api.md +++ b/packages/runtime/container-runtime/api-report/container-runtime.legacy.alpha.api.md @@ -32,7 +32,7 @@ export enum ContainerMessageType { Rejoin = "rejoin" } -// @alpha +// @alpha @deprecated export class ContainerRuntime extends TypedEventEmitter implements IContainerRuntime, IRuntime, ISummarizerRuntime, ISummarizerInternalsProvider, IProvideFluidHandleContext { protected constructor(context: IContainerContext, registry: IFluidDataStoreRegistry, metadata: IContainerRuntimeMetadata | undefined, electedSummarizerData: ISerializedElection | undefined, chunks: [string, string[]][], dataStoreAliasMap: [string, string][], runtimeOptions: Readonly> & IContainerRuntimeOptions>, containerScope: FluidObject, baseLogger: ITelemetryBaseLogger, existing: boolean, blobManagerSnapshot: IBlobManagerLoadInfo, _storage: IDocumentStorageService, createIdCompressor: () => Promise, documentsSchemaController: DocumentsSchemaController, featureGatesForTelemetry: Record, provideEntryPoint: (containerRuntime: IContainerRuntime) => Promise, requestHandler?: ((request: IRequest, runtime: IContainerRuntime) => Promise) | undefined, summaryConfiguration?: ISummaryConfiguration, recentBatchInfo?: [number, string][]); // (undocumented) diff --git a/packages/runtime/container-runtime/src/containerRuntime.ts b/packages/runtime/container-runtime/src/containerRuntime.ts index b71916f96ce9..2f1a413b5782 100644 --- a/packages/runtime/container-runtime/src/containerRuntime.ts +++ b/packages/runtime/container-runtime/src/containerRuntime.ts @@ -863,6 +863,10 @@ export async function loadContainerRuntime( /** * Represents the runtime of the container. Contains helper functions/state of the container. * It will define the store level mappings. + * + * @deprecated To be removed from the Legacy-Alpha API in version 2.20.0. + * Use the loadContainerRuntime function and interfaces IContainerRuntime / IRuntime instead. + * * @legacy * @alpha */ diff --git a/packages/runtime/runtime-utils/api-report/runtime-utils.legacy.alpha.api.md b/packages/runtime/runtime-utils/api-report/runtime-utils.legacy.alpha.api.md index ef220d91ce46..8e6c41e27586 100644 --- a/packages/runtime/runtime-utils/api-report/runtime-utils.legacy.alpha.api.md +++ b/packages/runtime/runtime-utils/api-report/runtime-utils.legacy.alpha.api.md @@ -52,17 +52,13 @@ export class RequestParser implements IRequest { // @alpha (undocumented) export abstract class RuntimeFactoryHelper implements IRuntimeFactory { - // (undocumented) hasInitialized(_runtime: T): Promise; - // (undocumented) instantiateFirstTime(_runtime: T): Promise; - // (undocumented) instantiateFromExisting(_runtime: T): Promise; // (undocumented) instantiateRuntime(context: IContainerContext, existing: boolean): Promise; // (undocumented) get IRuntimeFactory(): this; - // (undocumented) abstract preInitialize(context: IContainerContext, existing: boolean): Promise; } diff --git a/packages/runtime/runtime-utils/src/runtimeFactoryHelper.ts b/packages/runtime/runtime-utils/src/runtimeFactoryHelper.ts index e0c32e3ce8e5..d7033ae3de82 100644 --- a/packages/runtime/runtime-utils/src/runtimeFactoryHelper.ts +++ b/packages/runtime/runtime-utils/src/runtimeFactoryHelper.ts @@ -31,11 +31,30 @@ export abstract class RuntimeFactoryHelper implements IRu return runtime; } + /** + * Called at the start of initializing a container, to create the container runtime instance. + * @param context - The context for the container being initialized + * @param existing - Whether the container already exists and is being loaded (else it's being created new just now) + */ public abstract preInitialize( context: IContainerContext, existing: boolean, ): Promise; + /** + * Called the one time the container is created, and not on any subsequent load. + * i.e. only when it's initialized on the client that first created it + * @param runtime - The runtime for the container being initialized + */ public async instantiateFirstTime(_runtime: T): Promise {} + /** + * Called every time the container runtime is loaded for an existing container. + * i.e. every time it's initialized _except_ for when it is first created + * @param runtime - The runtime for the container being initialized + */ public async instantiateFromExisting(_runtime: T): Promise {} + /** + * Called at the end of initializing a container, after the runtime has been created or loaded. + * @param runtime - The runtime for the container being initialized + */ public async hasInitialized(_runtime: T): Promise {} } diff --git a/packages/test/test-service-load/src/loadTestDataStore.ts b/packages/test/test-service-load/src/loadTestDataStore.ts index 6efc5ce107ef..291a16f3b2b3 100644 --- a/packages/test/test-service-load/src/loadTestDataStore.ts +++ b/packages/test/test-service-load/src/loadTestDataStore.ts @@ -13,6 +13,7 @@ import { } from "@fluidframework/aqueduct/internal"; import { ILoaderOptions } from "@fluidframework/container-definitions/internal"; import { + // eslint-disable-next-line import/no-deprecated -- ContainerRuntime class to be moved to internal scope ContainerRuntime, IContainerRuntimeOptions, } from "@fluidframework/container-runtime/internal"; @@ -134,6 +135,7 @@ class LoadTestDataStoreModel { // If we did not create the data store above, load it by getting its url. if (gcDataStore === undefined) { const gcDataStoreId = root.get(gcDataStoreIdKey); + // eslint-disable-next-line import/no-deprecated -- ContainerRuntime class to be moved to internal scope const response = await (containerRuntime as ContainerRuntime).resolveHandle({ url: `/${gcDataStoreId}`, }); diff --git a/packages/test/test-utils/src/testContainerRuntimeFactory.ts b/packages/test/test-utils/src/testContainerRuntimeFactory.ts index 138ef3e2c7a7..6dd6d818f839 100644 --- a/packages/test/test-utils/src/testContainerRuntimeFactory.ts +++ b/packages/test/test-utils/src/testContainerRuntimeFactory.ts @@ -5,6 +5,7 @@ import { IContainerContext, IRuntime } from "@fluidframework/container-definitions/internal"; import { + // eslint-disable-next-line import/no-deprecated -- ContainerRuntime class to be moved to internal scope ContainerRuntime, DefaultSummaryConfiguration, type IContainerRuntimeOptionsInternal, @@ -57,7 +58,9 @@ interface backCompat_ContainerRuntime { runtimeOptions?: IContainerRuntimeOptionsInternal, containerScope?: FluidObject, existing?: boolean, + // eslint-disable-next-line import/no-deprecated -- ContainerRuntime class to be moved to internal scope containerRuntimeCtor?: typeof ContainerRuntime, + // eslint-disable-next-line import/no-deprecated -- ContainerRuntime class to be moved to internal scope ): Promise; } @@ -66,6 +69,7 @@ interface backCompat_ContainerRuntime { * @internal */ export const createTestContainerRuntimeFactory = ( + // eslint-disable-next-line import/no-deprecated -- ContainerRuntime class to be moved to internal scope containerRuntimeCtor: typeof ContainerRuntime, ) => { return class extends RuntimeFactoryHelper { @@ -88,6 +92,7 @@ export const createTestContainerRuntimeFactory = ( super(); } + // eslint-disable-next-line import/no-deprecated -- ContainerRuntime class to be moved to internal scope public async instantiateFirstTime(runtime: ContainerRuntime): Promise { // Back-compat - old code does not return IDataStore for rootContext.attachRuntime() call! // Thus need to leverage old API createDetachedRootDataStore() that is gone in latest releases. @@ -106,6 +111,7 @@ export const createTestContainerRuntimeFactory = ( assert(result === "Success" || result === undefined, "success"); } + // eslint-disable-next-line import/no-deprecated -- ContainerRuntime class to be moved to internal scope public async instantiateFromExisting(runtime: ContainerRuntime): Promise { // Validate we can load root data stores. // We should be able to load any data store that was created in initializeFirstTime! @@ -184,4 +190,5 @@ export const createTestContainerRuntimeFactory = ( * A container runtime factory that allows you to set runtime options * @internal */ +// eslint-disable-next-line import/no-deprecated -- ContainerRuntime class to be moved to internal scope export const TestContainerRuntimeFactory = createTestContainerRuntimeFactory(ContainerRuntime);