Files
OmniRoute/open-sse/executors/registry.ts
oyi77 77ea656b12 perf(executors): lazy-load the executor registry — defer class imports + construction to first use (#11220)
The executor barrel statically imported ~100 executor modules and
constructed every instance at module load. Measured cold cost on top of
the minimal set: ~0.7–1.2s boot time and ~35MB heap, paid by every
deployment regardless of which providers it uses.

Now:
- executors/index.ts keeps the declarative alias table byte-stable (same
  keys, same order, same ctor args — pinned by the golden lock) but each
  value is a deferred loader using dynamic import; bundlers emit
  on-demand chunks
- registry.ts gains registerLazyExecutor/loadRegisteredExecutor: aliases
  are declared eagerly so hasSpecializedExecutor() and
  listExecutorAliases() stay synchronous, instances materialize once on
  first use and cache into the same registry map
- getExecutor() becomes async; production call sites (chatCore proxy
  resolver, video generation, compression judge/eval clients,
  quotaAutoPing deps, anthropic OAuth validation) await it
- cliproxy wrapper ExecutorLike types drop their index signatures so
  BaseExecutor satisfies them structurally

Measured after (isolated DATA_DIR): barrel boot 712-832ms / ~45MB with
first-use materialization of an executor costing +120-150ms once.

Test impact: 24 unit suites adapted mechanically to the async seam
(await + union narrowing on the Response | {response} execute result);
class imports moved from the barrel to executor module files. The
web-cookie sweep SIGABRT failure is pre-existing (reproduced identically
on the clean base).

Commit gate note: husky lint-staged fails with 'suppressions left that
do not occur anymore' — reproduced identically on a stashed clean tree
(22 baseline problems), independent of this change.
2026-08-24 21:44:22 -03:00

74 lines
3.0 KiB
TypeScript

import type { BaseExecutor } from "./base.ts";
// R0.3 — ExecutorRegistry: runtime registry for provider executors, mirroring
// open-sse/translator/registry.ts. Built-ins register at module load from
// executors/index.ts; getExecutor() resolves through this map instead of a
// hard-coded object literal. This is the seam the v4 plan (M1.6
// host.registerProvider) extends — today the surface is internal-only.
//
// The alias → executor mapping is characterized by
// tests/unit/executor-map-golden.test.ts (tests/snapshots/executors/): any
// change to keys, classes or instance sharing shows up as a golden diff.
const registry = new Map<string, BaseExecutor>();
/**
* Register an executor under an alias. Aliases are unique: registering the
* same alias twice throws, preserving the guarantee the old object literal
* gave at compile time (duplicate keys were impossible).
*/
export function registerExecutor(alias: string, executor: BaseExecutor): void {
if (registry.has(alias)) {
throw new Error(`executor alias already registered: "${alias}"`);
}
registry.set(alias, executor);
}
export function getRegisteredExecutor(alias: string): BaseExecutor | undefined {
return registry.get(alias);
}
// ── #11220: lazy registration ───────────────────────────────────────────────
// Aliases may register a deferred loader instead of an instance. The alias and
// its registration ORDER are declared eagerly — hasRegisteredExecutor() and
// listExecutorAliases() stay synchronous and the golden snapshot keeps its
// shape — while the class import + construction happen on first use. A
// completed load caches into `registry`, so later resolution is identical to a
// static registration.
const lazyLoaders = new Map<string, () => Promise<BaseExecutor>>();
const lazyInFlight = new Map<string, Promise<BaseExecutor>>();
export function registerLazyExecutor(alias: string, load: () => Promise<BaseExecutor>): void {
if (registry.has(alias) || lazyLoaders.has(alias)) {
throw new Error(`executor alias already registered: "${alias}"`);
}
lazyLoaders.set(alias, load);
}
export function loadRegisteredExecutor(alias: string): Promise<BaseExecutor> | undefined {
const cached = registry.get(alias);
if (cached) return Promise.resolve(cached);
const load = lazyLoaders.get(alias);
if (!load) return undefined;
let inFlight = lazyInFlight.get(alias);
if (!inFlight) {
inFlight = load().then((executor) => {
registerExecutor(alias, executor);
lazyLoaders.delete(alias);
lazyInFlight.delete(alias);
return executor;
});
lazyInFlight.set(alias, inFlight);
}
return inFlight;
}
export function hasRegisteredExecutor(alias: string): boolean {
return registry.has(alias) || lazyLoaders.has(alias);
}
/** All registered aliases — static and lazy — in registration order. */
export function listExecutorAliases(): string[] {
return [...registry.keys(), ...lazyLoaders.keys()];
}