Retry & Errors
asimo provides automatic retry with exponential backoff for asynchronous service loading, plus a structured error API for debugging.
Retry Mechanism
Retry applies to async factories and bundles — not sync factories (sync factories execute once and their result is cached).
Configuration Levels
Retry can be configured at two levels, in order of precedence:
- Per-service (highest priority)
- Per-container via
AsimoConfig
If none of these configurations are provided, the built-in default will be used: 2 retries, 1000ms base delay
// 1. Per-servicefactory({ provide: UNSTABLE_SVC, load: async () => mightFail(), maxRetries: 5, retryDelayMs: 500,});
// 2. Per-containerconst app = createContainer({ name: "app", config: { maxRetries: 3, retryDelayMs: 2000, }, services: [...],});Note: to share the same configuration across the application, the standard practice
is to define a global config singleton and inject it in each container:
import { config } from "./container-config";
const app = createContainer({ name: "app", config, services: [...],});Exponential Backoff Formula
delay(n) = baseDelay * 2^n
Example with baseDelay = 1000ms, maxRetries = 3: Attempt 1: immediate Attempt 2: 1000ms delay Attempt 3: 2000ms delay Attempt 4: 4000ms delay → Total: 4 attempts (1 + 3 retries)What Gets Retried
- Async factory
load()that throws a non-AsimoError. - Bundle
load()that throws a non-AsimoError.
What Does NOT Get Retried
AsimoError— these are structural errors (service not found, circular bundle) and retrying would not help.- Sync factories — retry params on a sync factory produce a compile-time error.
factory({ provide: SYNC_IID, maxRetries: 3, // ❌ TypeScript error: RetryNotSupportedForSyncIID});Error Types
AsimoError
Thrown for runtime configuration errors — primarily “service not found” and circular bundle detection.
import { AsimoError } from "@asimojs/asimo";“Service not found” is not a normal runtime concern.
If types are properly used (IIDs declared independencies, noanycasts), TypeScript catches missing services at compile time viaServiceDependencyNotRegistered. AnAsimoErrorfor “Service not found” at runtime means types were bypassed — for instance by callingcontainer.get()with an unregistered IID through aContainer<any>reference, or by usinggetOptional/fetchOptionalwithout a proper fallback.
// This compiles — but will throw at runtime because the IID is not registered.// The compiler only protects you when dependencies are declared in factory()/bundle().const c: Container<any> = createContainer({ name: "empty" });c.get(SOME_IID); // throws AsimoError at runtimeIn contrast, circular bundle detection is always a runtime concern (bundles depend on dynamic import() chains that can’t be validated at compile time).
Properties:
message— prefixed with[Asimo], includes the container pathcontainer— the container path where the error occurredname—"AsimoError"
AsimoLoadError
A subclass of AsimoError thrown when a service load fails after exhausting retries:
import { AsimoLoadError } from "@asimojs/asimo";
try { await container.fetch(UNSTABLE_SVC);} catch (err) { if (err instanceof AsimoLoadError) { console.log(err.message); // "[Asimo] Load failed for ... after 4 attempts at /app" console.log(err.container); // "/app" console.log(err.cause); // The original error that caused the failure console.log(err.name); // "AsimoLoadError" }}Lifecycle Hooks
AsimoConfig provides two hooks for observing service loading:
const app = createContainer({ name: "app", config: { onLoad(iid, container) { // Called when a service loads successfully (factory or bundle) console.log(`Service loaded: ${iid.ns} in ${container.path}`); }, onError(error, container) { // Called when an AsimoError occurs during loading console.error(`Error in ${container.path}: ${error.message}`); }, }, services: [...],});onLoad— fires at most once per(iid, container)pair on successful load. Useful for instrumentation, logging, or performance tracking.onError— fires whenever anAsimoErroris thrown during service resolution. Use for error reporting or graceful degradation.
Error Messages
All asimo errors include the failing container path, making them easy to trace in complex hierarchies:
[Asimo] Service not found: app.services.Missing at /app/feature-a/request-42This tells you:
- The service
app.services.Missingcould not be found - The error occurred in the container at path
/app/feature-a/request-42 - The full parent chain: root
app→ childfeature-a→ childrequest-42
A “Service not found” error at runtime means the type system was bypassed (e.g.,
Container<any>,any-typed IIDs, orgetOptionalwithout a null check). With proper typing, the compiler catches missing services before the code runs.