or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

compatibility-management.mddatastore-operations.mdgarbage-collection.mdhandle-management.mdindex.mdruntime-factories.mdstorage-utilities.mdsummary-management.mdtelemetry-utilities.md
tile.json

runtime-factories.mddocs/

Runtime Factories ⚠️ Legacy API

Abstract base classes and helpers for implementing container runtime factories with standardized lifecycle management. These utilities provide a foundation for creating runtime factories that handle container initialization, loading, and lifecycle events.

⚠️ Legacy API Warning: The RuntimeFactoryHelper class is part of the legacy API surface and is only available via the /legacy import path. This API may be deprecated in future versions. Consider using modern runtime factory patterns from the main package exports.

Available APIs

RuntimeFactoryHelper ⚠️ Legacy API

Abstract base class that provides the standard implementation pattern for runtime factories, with hooks for customizing initialization behavior.

Import Path: @fluidframework/runtime-utils/legacy

⚠️ This is a legacy API that may change or be removed in future versions. Use with caution in production code.

/**
 * Helper base class for implementing runtime factories
 * @template T - The type of runtime to create, defaults to IContainerRuntime
 */
abstract class RuntimeFactoryHelper<T = IContainerRuntime> implements IRuntimeFactory {
  /** Get the IRuntimeFactory interface */
  get IRuntimeFactory(): this;
  
  /**
   * Main runtime instantiation method called by the container
   * @param context - The container context
   * @param existing - Whether this is loading an existing container (true) or creating new (false)
   * @returns Promise resolving to the created runtime
   */
  instantiateRuntime(context: IContainerContext, existing: boolean): Promise<IRuntime>;
  
  /**
   * Called at the start of initializing a container to create the container runtime instance
   * Must be implemented by subclasses to create the specific runtime type
   * @param context - The container context
   * @param existing - Whether this is loading an existing container
   * @returns Promise resolving to the runtime instance
   */
  abstract preInitialize(
    context: IContainerContext,
    existing: boolean
  ): Promise<IRuntime & T>;
  
  /**
   * Called the one time the container is created (not on subsequent loads)
   * Override to perform first-time initialization logic
   * @param runtime - The runtime instance that was created
   * @returns Promise that resolves when initialization is complete
   */
  instantiateFirstTime(runtime: T): Promise<void>;
  
  /**
   * Called every time the container runtime is loaded for an existing container
   * Override to perform load-time initialization logic
   * @param runtime - The runtime instance that was loaded
   * @returns Promise that resolves when initialization is complete
   */
  instantiateFromExisting(runtime: T): Promise<void>;
  
  /**
   * Called at the end of initializing a container
   * Override to perform final initialization steps
   * @param runtime - The runtime instance that has been initialized
   * @returns Promise that resolves when finalization is complete
   */
  hasInitialized(runtime: T): Promise<void>;
}

Usage Examples:

import { RuntimeFactoryHelper } from "@fluidframework/runtime-utils/legacy";
import { ContainerRuntime, IContainerRuntimeOptions } from "@fluidframework/container-runtime";

// Custom runtime factory implementation
class MyRuntimeFactory extends RuntimeFactoryHelper<ContainerRuntime> {
  constructor(
    private readonly registryEntries: NamedFluidDataStoreRegistryEntries,
    private readonly runtimeOptions?: IContainerRuntimeOptions
  ) {
    super();
  }
  
  // Required: Create the runtime instance
  async preInitialize(
    context: IContainerContext,
    existing: boolean
  ): Promise<IRuntime & ContainerRuntime> {
    const runtime = await ContainerRuntime.loadRuntime({
      context,
      registryEntries: this.registryEntries,
      existing,
      runtimeOptions: this.runtimeOptions,
    });
    
    return runtime;
  }
  
  // Optional: First-time container creation logic
  async instantiateFirstTime(runtime: ContainerRuntime): Promise<void> {
    console.log("Creating new container - setting up initial data stores");
    
    // Create default data stores
    await runtime.createDataStore("main-data-store");
    await runtime.createDataStore("settings-data-store");
    
    // Set up initial configuration
    const configDataStore = await runtime.createDataStore("config");
    const config = await configDataStore.entryPoint.get();
    await config.initialize({
      version: "1.0",
      created: new Date().toISOString()
    });
  }
  
  // Optional: Existing container load logic  
  async instantiateFromExisting(runtime: ContainerRuntime): Promise<void> {
    console.log("Loading existing container - performing migration checks");
    
    // Check for data migrations
    const configDataStore = await runtime.getDataStore("config");
    const config = await configDataStore.entryPoint.get();
    const currentVersion = await config.getVersion();
    
    if (needsMigration(currentVersion)) {
      await performMigration(runtime, currentVersion);
    }
  }
  
  // Optional: Final initialization logic
  async hasInitialized(runtime: ContainerRuntime): Promise<void> {
    console.log("Runtime initialization complete - setting up monitoring");
    
    // Set up telemetry and monitoring
    runtime.on("dispose", () => {
      console.log("Runtime disposed");
    });
    
    runtime.on("connected", () => {
      console.log("Runtime connected");
    });
    
    runtime.on("disconnected", () => {
      console.log("Runtime disconnected");
    });
  }
}

// Usage
const runtimeFactory = new MyRuntimeFactory(
  [
    ["my-data-store", Promise.resolve(MyDataStoreFactory)],
    ["settings-store", Promise.resolve(SettingsStoreFactory)]
  ],
  {
    summaryOptions: { summaryConfigOverrides: { state: "disabled" } },
    gcOptions: { gcAllowed: true }
  }
);

// The runtime factory can now be used with container loading
const container = await loader.createDetachedContainer(codeDetails);

Advanced Runtime Factory Patterns

// Multi-tenant runtime factory
class MultiTenantRuntimeFactory extends RuntimeFactoryHelper<ContainerRuntime> {
  constructor(
    private tenantId: string,
    private tenantConfig: TenantConfiguration
  ) {
    super();
  }
  
  async preInitialize(
    context: IContainerContext, 
    existing: boolean
  ): Promise<IRuntime & ContainerRuntime> {
    // Customize runtime options based on tenant
    const runtimeOptions: IContainerRuntimeOptions = {
      summaryOptions: this.tenantConfig.summaryOptions,
      gcOptions: this.tenantConfig.gcOptions,
      compressionOptions: this.tenantConfig.compressionOptions
    };
    
    return ContainerRuntime.loadRuntime({
      context,
      registryEntries: this.getRegistryForTenant(this.tenantId),
      existing,
      runtimeOptions
    });
  }
  
  async instantiateFirstTime(runtime: ContainerRuntime): Promise<void> {
    // Set up tenant-specific initial state
    await this.createTenantDataStores(runtime);
    await this.applyTenantPolicies(runtime);
  }
  
  async instantiateFromExisting(runtime: ContainerRuntime): Promise<void> {
    // Validate tenant access and apply updates
    await this.validateTenantAccess(runtime);
    await this.updateTenantPolicies(runtime);
  }
  
  private async createTenantDataStores(runtime: ContainerRuntime): Promise<void> {
    const tenantStores = this.tenantConfig.requiredDataStores;
    for (const storeConfig of tenantStores) {
      await runtime.createDataStore(storeConfig.type, storeConfig.id);
    }
  }
}

// Development/Production runtime factory
class EnvironmentAwareRuntimeFactory extends RuntimeFactoryHelper<ContainerRuntime> {
  constructor(
    private environment: "development" | "production",
    private baseRegistryEntries: NamedFluidDataStoreRegistryEntries
  ) {
    super();
  }
  
  async preInitialize(
    context: IContainerContext,
    existing: boolean
  ): Promise<IRuntime & ContainerRuntime> {
    const runtimeOptions = this.getRuntimeOptionsForEnvironment();
    const registryEntries = this.getRegistryEntriesForEnvironment();
    
    return ContainerRuntime.loadRuntime({
      context,
      registryEntries,
      existing,
      runtimeOptions
    });
  }
  
  async hasInitialized(runtime: ContainerRuntime): Promise<void> {
    if (this.environment === "development") {
      // Add development-only debugging and logging
      this.setupDevelopmentTooling(runtime);
    } else {
      // Add production monitoring and telemetry
      this.setupProductionMonitoring(runtime);
    }
  }
  
  private getRuntimeOptionsForEnvironment(): IContainerRuntimeOptions {
    if (this.environment === "development") {
      return {
        summaryOptions: { summaryConfigOverrides: { state: "disabled" } },
        gcOptions: { gcAllowed: false }, // Disable GC in dev for easier debugging
        compressionOptions: { minimumBatchSizeInBytes: 0 } // No compression in dev  
      };
    } else {
      return {
        summaryOptions: { summaryConfigOverrides: { state: "enabled" } },
        gcOptions: { gcAllowed: true },
        compressionOptions: { minimumBatchSizeInBytes: 1024 }
      };
    }
  }
}

// Testing-focused runtime factory
class TestRuntimeFactory extends RuntimeFactoryHelper<ContainerRuntime> {
  private testHooks: TestHooks[] = [];
  
  addTestHook(hook: TestHook): void {
    this.testHooks.push(hook);
  }
  
  async preInitialize(
    context: IContainerContext,
    existing: boolean
  ): Promise<IRuntime & ContainerRuntime> {
    // Create runtime with test-friendly options
    const runtime = await ContainerRuntime.loadRuntime({
      context,
      registryEntries: this.getTestRegistryEntries(),
      existing,
      runtimeOptions: {
        summaryOptions: { summaryConfigOverrides: { state: "disabled" } },
        gcOptions: { gcAllowed: false }
      }
    });
    
    // Apply test hooks
    for (const hook of this.testHooks) {
      hook.apply(runtime);
    }
    
    return runtime;
  }
  
  async instantiateFirstTime(runtime: ContainerRuntime): Promise<void> {
    // Create predictable test data
    await this.createTestDataStores(runtime);
  }
  
  private async createTestDataStores(runtime: ContainerRuntime): Promise<void> {
    // Create data stores with known IDs for testing
    await runtime.createDataStore("test-store-1", "test-1");
    await runtime.createDataStore("test-store-2", "test-2");
  }
}