perf(server): do not watch bundled plugins for file changes (#16677)

Bundled sandbox-provider plugins are installed from local paths inside the image, so production started a chokidar dev watcher for each of them over files that never change. createPluginDevWatcher now takes unwatchedRoots (compared in resolved and real-path form), and the app passes the bundled plugin catalog root; plugins installed elsewhere are watched as before, and a plugin moving into an unwatched root closes its old watcher and cancels any pending restart.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
Devin FoleyandPaperclip authored and GitHub committed 2026-10-17 18:39:11 -07:00
1 parent d30648dee8
commit bebeb389f1
3 files changed
+91 -2

No files matched your search

+19 -1
View File
@@ -14,7 +14,7 @@
* @see PLUGIN_SPEC.md §27.2 — Local Development Workflow
*/
import chokidar, { type FSWatcher } from "chokidar";
import { existsSync, readFileSync, readdirSync, statSync } from "node:fs";
import { existsSync, readFileSync, readdirSync, realpathSync, statSync } from "node:fs";
import path from "node:path";
import { logger } from "../middleware/logger.js";
import type { PluginLifecycleManager } from "./plugin-lifecycle.js";
@@ -160,6 +160,7 @@ export function createPluginDevWatcher(
lifecycle: PluginLifecycleManager,
resolvePluginPackagePath?: ResolvePluginPackagePath,
fsDeps?: PluginDevWatcherFsDeps,
options: { unwatchedRoots?: readonly string[] } = {},
): PluginDevWatcher {
const watchers = new Map<string, { watcher: FSWatcher; packagePath: string }>();
const debounceTimers = new Map<string, ReturnType<typeof setTimeout>>();
@@ -167,6 +168,19 @@ export function createPluginDevWatcher(
// Never reuse an identity after unwatching: an older lookup may still finish.
let registrationGeneration = 0;
const fileExists = fsDeps?.existsSync ?? existsSync;
const pathForms = (target: string) => {
const resolved = path.resolve(target);
try {
return [resolved, realpathSync(resolved)];
} catch {
return [resolved];
}
};
const unwatchedRoots = (options.unwatchedRoots ?? []).flatMap(pathForms);
const isUnwatched = (absPath: string) => pathForms(absPath).some((candidate) => unwatchedRoots.some((root) => {
const relative = path.relative(root, candidate);
return relative === "" || (!relative.startsWith("..") && !path.isAbsolute(relative));
}));
log.info(
{ resolvesInstalledPlugins: Boolean(resolvePluginPackagePath) },
"plugin-dev-watcher: initialized",
@@ -179,6 +193,10 @@ export function createPluginDevWatcher(
// watcher only while it still targets the installed package path.
if (watchers.get(pluginId)?.packagePath === absPath) return;
unwatchPlugin(pluginId);
if (isUnwatched(absPath)) {
log.debug({ pluginId, packagePath: absPath }, "plugin-dev-watcher: plugin path is not watched");
return;
}
if (!fileExists(absPath)) {
log.warn(