Fluid container loader providing core container loading functionality for the Fluid Framework
56
Pending
Does it follow best practices?
Impact
56%
0.98xAverage score across 10 eval scenarios
Pending
The risk profile of this skill
The utilities module provides helper functions for container management, URL handling, location redirection, and compatibility checks.
Waits for a container to finish synchronizing with the latest state from the service.
function waitContainerToCatchUp(container: IContainer): Promise<boolean>;This function is particularly useful after reconnection events to ensure the container has processed all pending operations.
import { waitContainerToCatchUp } from "@fluidframework/container-loader";
async function handleReconnection(container: IContainer) {
console.log("Container reconnected, waiting to catch up...");
const success = await waitContainerToCatchUp(container);
if (success) {
console.log("Container successfully caught up with latest state");
// Safe to continue with operations
await performContainerOperations(container);
} else {
console.error("Container failed to catch up within timeout");
// Handle failure scenario
await handleCatchUpFailure(container);
}
}
// Use with connection event handlers
container.on("connected", () => handleReconnection(container));Attempts to parse a URL into a compatible resolved URL structure.
function tryParseCompatibleResolvedUrl(url: string): IParsedUrl | undefined;Returns a parsed URL object if the URL can be parsed, or undefined if parsing fails.
import { tryParseCompatibleResolvedUrl } from "@fluidframework/container-loader";
import type { IParsedUrl } from "@fluidframework/container-loader";
function handleUrlParsing(urlString: string) {
const parsedUrl: IParsedUrl | undefined = tryParseCompatibleResolvedUrl(urlString);
if (parsedUrl) {
console.log("Successfully parsed URL:");
console.log(" ID:", parsedUrl.id);
console.log(" Path:", parsedUrl.path);
console.log(" Query:", parsedUrl.query);
console.log(" Version:", parsedUrl.version);
// Use parsed components
if (parsedUrl.version) {
console.log(`Loading specific version: ${parsedUrl.version}`);
}
} else {
console.log("Unable to parse URL:", urlString);
// Handle parsing failure
}
}Resolves requests with automatic handling of location redirection errors.
function resolveWithLocationRedirectionHandling<T>(
api: (request: IRequest) => Promise<T>,
request: IRequest,
urlResolver: IUrlResolver,
logger?: ITelemetryBaseLogger
): Promise<T>;This utility wraps API calls to automatically handle location redirection scenarios common in distributed Fluid deployments.
import {
resolveWithLocationRedirectionHandling
} from "@fluidframework/container-loader";
import type {
IRequest,
IUrlResolver,
ITelemetryBaseLogger
} from "@fluidframework/container-loader";
async function loadContainerWithRedirection(
request: IRequest,
urlResolver: IUrlResolver,
logger?: ITelemetryBaseLogger
) {
const containerLoadApi = async (req: IRequest) => {
// Your container loading logic
const resolvedUrl = await urlResolver.resolve(req);
return await loadContainerFromUrl(resolvedUrl);
};
try {
const container = await resolveWithLocationRedirectionHandling(
containerLoadApi,
request,
urlResolver,
logger
);
console.log("Container loaded successfully:", container.id);
return container;
} catch (error) {
console.error("Failed to load container after redirection handling:", error);
throw error;
}
}function isLocationRedirectionError(error: any): boolean;Determines if an error is a location redirection error that can be handled automatically.
import { isLocationRedirectionError } from "@fluidframework/container-loader";
async function handleContainerLoadError(error: any, request: IRequest) {
if (isLocationRedirectionError(error)) {
console.log("Detected location redirection error");
// Extract new location from error
const redirectUrl = error.redirectUrl || error.location;
if (redirectUrl) {
console.log(`Redirecting to: ${redirectUrl}`);
// Create new request with redirected URL
const redirectedRequest: IRequest = {
...request,
url: redirectUrl
};
// Retry with redirected URL
return await loadContainer(redirectedRequest);
}
}
// Not a redirection error, re-throw
throw error;
}Loads a container in a paused state, optionally up to a specific sequence number.
function loadContainerPaused(
loaderProps: ILoaderProps,
request: IRequest,
loadToSequenceNumber?: number,
signal?: AbortSignal,
): Promise<IContainer>;This function is useful for loading containers for debugging, analysis, or when you need to examine state at a specific point in time.
import { loadContainerPaused } from "@fluidframework/container-loader";
import type { ILoaderProps, IRequest } from "@fluidframework/container-loader";
async function loadContainerForDebugging(
loaderProps: ILoaderProps,
request: IRequest,
targetSequenceNumber?: number
) {
// Create abort controller for timeout
const abortController = new AbortController();
const timeoutId = setTimeout(() => {
abortController.abort();
}, 30000); // 30 second timeout
try {
const pausedContainer = await loadContainerPaused(
loaderProps,
request,
targetSequenceNumber,
abortController.signal
);
clearTimeout(timeoutId);
console.log("Container loaded in paused state");
console.log("Current sequence number:", pausedContainer.deltaManager.lastSequenceNumber);
if (targetSequenceNumber) {
console.log(`Loaded up to sequence number: ${targetSequenceNumber}`);
}
// Examine container state while paused
const snapshot = pausedContainer.serialize();
console.log("Container snapshot length:", snapshot.length);
// Resume when ready
pausedContainer.resume();
return pausedContainer;
} catch (error) {
clearTimeout(timeoutId);
if (error.name === 'AbortError') {
console.error("Container loading timed out");
} else {
console.error("Error loading paused container:", error);
}
throw error;
}
}interface IParsedUrl {
id: string;
path: string;
query: string;
version: string | undefined;
}Represents the structure of a parsed Fluid URL with its constituent components.
The loader provides several compatibility constants for version checking and feature detection.
const loaderCoreCompatDetails: ILayerCompatDetails;
const loaderCompatDetailsForRuntime: ILayerCompatDetails;
const runtimeSupportRequirementsForLoader: ILayerCompatSupportRequirements;
const driverSupportRequirementsForLoader: ILayerCompatSupportRequirements;import {
loaderCoreCompatDetails,
loaderCompatDetailsForRuntime,
runtimeSupportRequirementsForLoader,
driverSupportRequirementsForLoader
} from "@fluidframework/container-loader";
function checkCompatibility() {
console.log("Loader core compatibility:", loaderCoreCompatDetails);
console.log("Runtime compatibility requirements:", runtimeSupportRequirementsForLoader);
console.log("Driver compatibility requirements:", driverSupportRequirementsForLoader);
// Use for version checking and feature detection
const isCompatible = checkVersionCompatibility(
runtimeVersion,
runtimeSupportRequirementsForLoader
);
if (!isCompatible) {
throw new Error("Runtime version incompatible with loader requirements");
}
}import {
resolveWithLocationRedirectionHandling,
isLocationRedirectionError,
waitContainerToCatchUp
} from "@fluidframework/container-loader";
async function robustContainerLoad(
request: IRequest,
loaderProps: ILoaderProps,
maxRetries: number = 3
): Promise<IContainer> {
const loader = new Loader(loaderProps);
let lastError: Error | undefined;
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
// Use redirection handling for robust loading
const container = await resolveWithLocationRedirectionHandling(
(req) => loader.resolve(req),
request,
loaderProps.urlResolver,
loaderProps.logger
);
// Wait for container to catch up
const success = await waitContainerToCatchUp(container);
if (!success) {
throw new Error("Container failed to catch up");
}
console.log(`Container loaded successfully on attempt ${attempt}`);
return container;
} catch (error) {
lastError = error as Error;
console.warn(`Container load attempt ${attempt} failed:`, error);
if (isLocationRedirectionError(error)) {
console.log("Redirection error will be retried");
} else if (attempt === maxRetries) {
console.error("Max retries exceeded");
break;
}
// Exponential backoff
const delay = Math.pow(2, attempt - 1) * 1000;
await new Promise(resolve => setTimeout(resolve, delay));
}
}
throw lastError || new Error("Container load failed after retries");
}import { tryParseCompatibleResolvedUrl } from "@fluidframework/container-loader";
function validateAndNormalizeUrl(urlString: string): string {
// First, try to parse the URL
const parsedUrl = tryParseCompatibleResolvedUrl(urlString);
if (!parsedUrl) {
throw new Error(`Invalid Fluid URL format: ${urlString}`);
}
// Validate required components
if (!parsedUrl.id) {
throw new Error("URL must contain a valid document ID");
}
// Normalize the URL components
const normalizedUrl = constructFluidUrl({
id: parsedUrl.id.trim(),
path: parsedUrl.path.startsWith('/') ? parsedUrl.path : `/${parsedUrl.path}`,
query: parsedUrl.query.startsWith('?') ? parsedUrl.query : `?${parsedUrl.query}`,
version: parsedUrl.version?.trim()
});
console.log(`Normalized URL: ${normalizedUrl}`);
return normalizedUrl;
}async function handleContainerErrors(
container: IContainer,
onError: (error: Error) => void
) {
container.on("closed", (error) => {
if (error) {
console.error("Container closed with error:", error);
if (isLocationRedirectionError(error)) {
console.log("Attempting recovery with redirection");
// Trigger redirection recovery
} else {
onError(error);
}
}
});
container.on("disconnected", async () => {
console.log("Container disconnected, waiting for reconnection...");
// Set up timeout for reconnection
const reconnectTimeout = setTimeout(() => {
console.error("Reconnection timeout exceeded");
onError(new Error("Failed to reconnect within timeout"));
}, 30000);
container.once("connected", async () => {
clearTimeout(reconnectTimeout);
console.log("Container reconnected");
try {
const success = await waitContainerToCatchUp(container);
if (!success) {
throw new Error("Failed to catch up after reconnection");
}
console.log("Container fully synchronized after reconnection");
} catch (error) {
onError(error as Error);
}
});
});
}evals
scenario-1
scenario-2
scenario-3
scenario-4
scenario-5
scenario-6
scenario-7
scenario-8
scenario-9
scenario-10