fix(models): handle watcher errors, close on shutdown, rewarm after i… · openclaw/openclaw@55cfe00
sjf
·
2026-05-22
·
via Recent Commits to openclaw:main
| Original file line number | Diff line number | Diff line change |
|---|
@@ -13,9 +13,14 @@ export type AuthProfilesWatcherHandle = {
|
13 | 13 | stop: () => Promise<void>; |
14 | 14 | }; |
15 | 15 | |
| 16 | +type WatcherLog = { |
| 17 | +warn: (msg: string) => void; |
| 18 | +}; |
| 19 | + |
16 | 20 | export function watchAuthProfilesForChanges(params: { |
17 | 21 | cfg: OpenClawConfig; |
18 | 22 | onChange: () => void; |
| 23 | +log?: WatcherLog; |
19 | 24 | }): AuthProfilesWatcherHandle { |
20 | 25 | const watchPaths = listAgentIds(params.cfg).map((agentId) => |
21 | 26 | path.join(resolveAgentDir(params.cfg, agentId), "auth-profiles.json"), |
@@ -25,16 +30,26 @@ export function watchAuthProfilesForChanges(params: {
|
25 | 30 | awaitWriteFinish: { stabilityThreshold: 200, pollInterval: 50 }, |
26 | 31 | usePolling: Boolean(process.env.VITEST), |
27 | 32 | }); |
| 33 | +let closed = false; |
28 | 34 | watcher.on("all", () => { |
29 | 35 | try { |
30 | 36 | params.onChange(); |
31 | 37 | } catch { |
32 | 38 | // onChange errors must not crash the watcher. |
33 | 39 | } |
34 | 40 | }); |
| 41 | +watcher.on("error", (err) => { |
| 42 | +if (closed) { |
| 43 | +return; |
| 44 | +} |
| 45 | +closed = true; |
| 46 | +params.log?.warn(`auth-profile watcher error: ${String(err)}`); |
| 47 | +void watcher.close().catch(() => {}); |
| 48 | +}); |
35 | 49 | return { |
36 | 50 | stop: async () => { |
37 | | -await watcher.close(); |
| 51 | +closed = true; |
| 52 | +await watcher.close().catch(() => {}); |
38 | 53 | }, |
39 | 54 | }; |
40 | 55 | } |
| Original file line number | Diff line number | Diff line change |
|---|
@@ -1019,18 +1019,42 @@ export async function startGatewayPostAttachRuntime(
|
1019 | 1019 | }); |
1020 | 1020 | |
1021 | 1021 | void sidecarsPromise |
1022 | | -.then(async () => { |
| 1022 | +.then(async (sidecarsResult) => { |
1023 | 1023 | if (params.minimalTestGateway) { |
1024 | 1024 | return; |
1025 | 1025 | } |
1026 | 1026 | const { clearCurrentProviderAuthState, warmCurrentProviderAuthState } = |
1027 | 1027 | await import("../agents/model-provider-auth.js"); |
1028 | 1028 | const { setAuthProfileFailureHook } = await import("../agents/auth-profiles.js"); |
1029 | 1029 | const { watchAuthProfilesForChanges } = await import("../agents/auth-profiles-watcher.js"); |
1030 | | -setAuthProfileFailureHook(() => clearCurrentProviderAuthState()); |
1031 | | -watchAuthProfilesForChanges({ |
| 1030 | +const scheduleAuthMapRewarm = (reason: string) => { |
| 1031 | +const startMs = Date.now(); |
| 1032 | +void warmCurrentProviderAuthState(params.cfgAtStart) |
| 1033 | +.then(() => { |
| 1034 | +params.log.info( |
| 1035 | +`provider auth state re-warmed (${reason}) in ${Date.now() - startMs}ms`, |
| 1036 | +); |
| 1037 | +}) |
| 1038 | +.catch((err) => { |
| 1039 | +params.log.warn(`provider auth state rewarm failed: ${String(err)}`); |
| 1040 | +}); |
| 1041 | +}; |
| 1042 | +setAuthProfileFailureHook(() => { |
| 1043 | +clearCurrentProviderAuthState(); |
| 1044 | +scheduleAuthMapRewarm("auth-profile-failure"); |
| 1045 | +}); |
| 1046 | +const authProfilesWatcher = watchAuthProfilesForChanges({ |
1032 | 1047 | cfg: params.cfgAtStart, |
1033 | | -onChange: () => clearCurrentProviderAuthState(), |
| 1048 | +onChange: () => { |
| 1049 | +clearCurrentProviderAuthState(); |
| 1050 | +scheduleAuthMapRewarm("auth-profiles.json change"); |
| 1051 | +}, |
| 1052 | +log: params.log, |
| 1053 | +}); |
| 1054 | +sidecarsResult.postReadySidecars.push({ |
| 1055 | +stop: () => { |
| 1056 | +void authProfilesWatcher.stop(); |
| 1057 | +}, |
1034 | 1058 | }); |
1035 | 1059 | const startMs = Date.now(); |
1036 | 1060 | await warmCurrentProviderAuthState(params.cfgAtStart); |
|
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。