mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-08-26 09:02:11 +03:00
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.
74 lines
3.0 KiB
TypeScript
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()];
|
|
}
|