Skip to content

Commit

Permalink
Deprecate ContainerRuntime class (#23331)
Browse files Browse the repository at this point in the history
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 <[email protected]>
Co-authored-by: Joshua Smithrud <[email protected]>
  • Loading branch information
3 people authored Dec 16, 2024
1 parent 35e9227 commit dc48446
Show file tree
Hide file tree
Showing 12 changed files with 93 additions and 19 deletions.
24 changes: 24 additions & 0 deletions .changeset/plain-mails-tan.md
Original file line number Diff line number Diff line change
@@ -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.
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down Expand Up @@ -89,7 +89,7 @@ export const loadCompositeRuntime = async (
compositeEntryPoint: CompositeEntryPoint,
runtimeOptions?: IContainerRuntimeOptions,
): Promise<IContainerRuntime & IRuntime> => {
const runtime = await ContainerRuntime.loadRuntime({
const runtime = await loadContainerRuntime({
context,
registryEntries: compositeEntryPoint.registryEntries,
provideEntryPoint: compositeEntryPoint.provideEntryPoint,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,9 @@ export class BaseContainerRuntimeFactory extends RuntimeFactoryHelper implements
protected containerHasInitialized(runtime: IContainerRuntime): Promise<void>;
protected containerInitializingFirstTime(runtime: IContainerRuntime): Promise<void>;
get IFluidDataStoreRegistry(): IFluidDataStoreRegistry;
// (undocumented)
instantiateFirstTime(runtime: ContainerRuntime): Promise<void>;
// (undocumented)
instantiateFromExisting(runtime: ContainerRuntime): Promise<void>;
// (undocumented)
instantiateFirstTime(runtime: IContainerRuntime): Promise<void>;
instantiateFromExisting(runtime: IContainerRuntime): Promise<void>;
// @deprecated
preInitialize(context: IContainerContext, existing: boolean): Promise<ContainerRuntime>;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -97,18 +98,36 @@ export class BaseContainerRuntimeFactory
this.registry = new FluidDataStoreRegistry(this.registryEntries);
}

public async instantiateFirstTime(runtime: ContainerRuntime): Promise<void> {
/**
* 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<void> {
await this.containerInitializingFirstTime(runtime);
await this.containerHasInitialized(runtime);
}

public async instantiateFromExisting(runtime: ContainerRuntime): Promise<void> {
/**
* 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<void> {
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<ContainerRuntime> {
const scope: Partial<IProvideFluidDependencySynthesizer> = context.scope;
if (this.dependencyContainer) {
Expand All @@ -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,
Expand Down
7 changes: 7 additions & 0 deletions packages/framework/attributor/src/mixinAttributor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down Expand Up @@ -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: {
Expand All @@ -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<IResponse>;
provideEntryPoint: (containerRuntime: IContainerRuntime) => Promise<FluidObject>;
// eslint-disable-next-line import/no-deprecated -- ContainerRuntime class to be moved to internal scope
}): Promise<ContainerRuntime> {
const {
context,
Expand All @@ -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;

Expand Down Expand Up @@ -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;
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ export enum ContainerMessageType {
Rejoin = "rejoin"
}

// @alpha
// @alpha @deprecated
export class ContainerRuntime extends TypedEventEmitter<IContainerRuntimeEvents> 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<Required<Omit<IContainerRuntimeOptions, "flushMode" | "enableGroupedBatching">> & IContainerRuntimeOptions>, containerScope: FluidObject, baseLogger: ITelemetryBaseLogger, existing: boolean, blobManagerSnapshot: IBlobManagerLoadInfo, _storage: IDocumentStorageService, createIdCompressor: () => Promise<IIdCompressor & IIdCompressorCore>, documentsSchemaController: DocumentsSchemaController, featureGatesForTelemetry: Record<string, boolean | number | undefined>, provideEntryPoint: (containerRuntime: IContainerRuntime) => Promise<FluidObject>, requestHandler?: ((request: IRequest, runtime: IContainerRuntime) => Promise<IResponse>) | undefined, summaryConfiguration?: ISummaryConfiguration, recentBatchInfo?: [number, string][]);
// (undocumented)
Expand Down
4 changes: 4 additions & 0 deletions packages/runtime/container-runtime/src/containerRuntime.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,17 +52,13 @@ export class RequestParser implements IRequest {

// @alpha (undocumented)
export abstract class RuntimeFactoryHelper<T = IContainerRuntime> implements IRuntimeFactory {
// (undocumented)
hasInitialized(_runtime: T): Promise<void>;
// (undocumented)
instantiateFirstTime(_runtime: T): Promise<void>;
// (undocumented)
instantiateFromExisting(_runtime: T): Promise<void>;
// (undocumented)
instantiateRuntime(context: IContainerContext, existing: boolean): Promise<IRuntime>;
// (undocumented)
get IRuntimeFactory(): this;
// (undocumented)
abstract preInitialize(context: IContainerContext, existing: boolean): Promise<IRuntime & T>;
}

Expand Down
19 changes: 19 additions & 0 deletions packages/runtime/runtime-utils/src/runtimeFactoryHelper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,30 @@ export abstract class RuntimeFactoryHelper<T = IContainerRuntime> 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<IRuntime & T>;
/**
* 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<void> {}
/**
* 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<void> {}
/**
* 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<void> {}
}
2 changes: 2 additions & 0 deletions packages/test/test-service-load/src/loadTestDataStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down Expand Up @@ -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}`,
});
Expand Down
7 changes: 7 additions & 0 deletions packages/test/test-utils/src/testContainerRuntimeFactory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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<ContainerRuntime>;
}

Expand All @@ -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 {
Expand All @@ -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<void> {
// 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.
Expand All @@ -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<void> {
// Validate we can load root data stores.
// We should be able to load any data store that was created in initializeFirstTime!
Expand Down Expand Up @@ -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);

0 comments on commit dc48446

Please sign in to comment.