mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-28 16:07:24 +00:00
fix(models): handle watcher errors, close on shutdown, rewarm after invalidate
Addresses three ClawSweeper findings on the fs-watcher commit: - [P1] auth-profile watcher now handles chokidar 'error' events (logs + closes once) mirroring the gateway config-reload pattern. Without this, an unhandled error from chokidar can crash the gateway. - [P2] auth-profile watcher handle is pushed into postReadySidecars so stopPostReadySidecarsAfterCloseStarted closes it on gateway shutdown. - [P2] auth-failure and file-change invalidation paths now schedule a background rewarm (with a 'reason=' log line). Without this, the next /models call after an invalidation paid the slow per-provider path until the next reload. The warmer's existing generation counter handles concurrent rewarms safely.
This commit is contained in:
@@ -13,9 +13,14 @@ export type AuthProfilesWatcherHandle = {
|
||||
stop: () => Promise<void>;
|
||||
};
|
||||
|
||||
type WatcherLog = {
|
||||
warn: (msg: string) => void;
|
||||
};
|
||||
|
||||
export function watchAuthProfilesForChanges(params: {
|
||||
cfg: OpenClawConfig;
|
||||
onChange: () => void;
|
||||
log?: WatcherLog;
|
||||
}): AuthProfilesWatcherHandle {
|
||||
const watchPaths = listAgentIds(params.cfg).map((agentId) =>
|
||||
path.join(resolveAgentDir(params.cfg, agentId), "auth-profiles.json"),
|
||||
@@ -25,6 +30,7 @@ export function watchAuthProfilesForChanges(params: {
|
||||
awaitWriteFinish: { stabilityThreshold: 200, pollInterval: 50 },
|
||||
usePolling: Boolean(process.env.VITEST),
|
||||
});
|
||||
let closed = false;
|
||||
watcher.on("all", () => {
|
||||
try {
|
||||
params.onChange();
|
||||
@@ -32,9 +38,18 @@ export function watchAuthProfilesForChanges(params: {
|
||||
// onChange errors must not crash the watcher.
|
||||
}
|
||||
});
|
||||
watcher.on("error", (err) => {
|
||||
if (closed) {
|
||||
return;
|
||||
}
|
||||
closed = true;
|
||||
params.log?.warn(`auth-profile watcher error: ${String(err)}`);
|
||||
void watcher.close().catch(() => {});
|
||||
});
|
||||
return {
|
||||
stop: async () => {
|
||||
await watcher.close();
|
||||
closed = true;
|
||||
await watcher.close().catch(() => {});
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1019,7 +1019,7 @@ export async function startGatewayPostAttachRuntime(
|
||||
});
|
||||
|
||||
void sidecarsPromise
|
||||
.then(async () => {
|
||||
.then(async (sidecarsResult) => {
|
||||
if (params.minimalTestGateway) {
|
||||
return;
|
||||
}
|
||||
@@ -1027,10 +1027,34 @@ export async function startGatewayPostAttachRuntime(
|
||||
await import("../agents/model-provider-auth.js");
|
||||
const { setAuthProfileFailureHook } = await import("../agents/auth-profiles.js");
|
||||
const { watchAuthProfilesForChanges } = await import("../agents/auth-profiles-watcher.js");
|
||||
setAuthProfileFailureHook(() => clearCurrentProviderAuthState());
|
||||
watchAuthProfilesForChanges({
|
||||
const scheduleAuthMapRewarm = (reason: string) => {
|
||||
const startMs = Date.now();
|
||||
void warmCurrentProviderAuthState(params.cfgAtStart)
|
||||
.then(() => {
|
||||
params.log.info(
|
||||
`provider auth state re-warmed (${reason}) in ${Date.now() - startMs}ms`,
|
||||
);
|
||||
})
|
||||
.catch((err) => {
|
||||
params.log.warn(`provider auth state rewarm failed: ${String(err)}`);
|
||||
});
|
||||
};
|
||||
setAuthProfileFailureHook(() => {
|
||||
clearCurrentProviderAuthState();
|
||||
scheduleAuthMapRewarm("auth-profile-failure");
|
||||
});
|
||||
const authProfilesWatcher = watchAuthProfilesForChanges({
|
||||
cfg: params.cfgAtStart,
|
||||
onChange: () => clearCurrentProviderAuthState(),
|
||||
onChange: () => {
|
||||
clearCurrentProviderAuthState();
|
||||
scheduleAuthMapRewarm("auth-profiles.json change");
|
||||
},
|
||||
log: params.log,
|
||||
});
|
||||
sidecarsResult.postReadySidecars.push({
|
||||
stop: () => {
|
||||
void authProfilesWatcher.stop();
|
||||
},
|
||||
});
|
||||
const startMs = Date.now();
|
||||
await warmCurrentProviderAuthState(params.cfgAtStart);
|
||||
|
||||
Reference in New Issue
Block a user