fix: cache registry promise and cap stderr buffer

- Cache the Promise instead of the resolved PluginRegistry to prevent
  concurrent callers from racing past the null check and creating
  multiple registries before loadFromConfig completes.
- Cap stderrChunks to 100 entries since only early startup errors
  (stale build detection) are checked — unbounded growth wastes memory
  for long-running dashboard processes.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Prateek 2026-02-18 14:09:08 +05:30
parent ba04f50656
commit 0a300e6c79
2 changed files with 15 additions and 7 deletions

View File

@ -69,9 +69,13 @@ export function registerDashboard(program: Command): void {
const stderrChunks: string[] = [];
const MAX_STDERR_CHUNKS = 100;
child.stderr?.on("data", (data: Buffer) => {
const text = data.toString();
stderrChunks.push(text);
if (stderrChunks.length < MAX_STDERR_CHUNKS) {
stderrChunks.push(text);
}
// Still show stderr to the user
process.stderr.write(data);
});

View File

@ -15,18 +15,22 @@ import {
type PluginRegistry,
} from "@composio/ao-core";
let cachedRegistry: PluginRegistry | null = null;
let registryPromise: Promise<PluginRegistry> | null = null;
/**
* Get or create the plugin registry.
* Cached to avoid re-importing all plugins on every call.
* Caches the Promise (not the resolved value) so concurrent callers
* await the same initialization rather than racing.
*/
async function getRegistry(config: OrchestratorConfig): Promise<PluginRegistry> {
if (!cachedRegistry) {
cachedRegistry = createPluginRegistry();
await cachedRegistry.loadFromConfig(config);
if (!registryPromise) {
registryPromise = (async () => {
const registry = createPluginRegistry();
await registry.loadFromConfig(config);
return registry;
})();
}
return cachedRegistry;
return registryPromise;
}
/**