From bdc595d1bd56264ef0db13aec05988a21caa5230 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Wed, 12 Aug 2026 05:56:01 -0700 Subject: [PATCH] fix(gateway): refresh health after account removal (#122620) --- src/gateway/server-methods/health.ts | 22 ++++------- .../server-methods/server-methods.test.ts | 37 +++++++++++++++++++ 2 files changed, 44 insertions(+), 15 deletions(-) diff --git a/src/gateway/server-methods/health.ts b/src/gateway/server-methods/health.ts index cf0e6dc82a3f..3315561b34a8 100644 --- a/src/gateway/server-methods/health.ts +++ b/src/gateway/server-methods/health.ts @@ -33,17 +33,6 @@ function shouldScheduleRequestRefresh( return true; } -function cachedAccountForRuntimeSnapshot(params: { - cachedChannel: ChannelHealthSummary | undefined; - accountId: string | undefined; -}): ChannelHealthSummary | undefined { - const accountId = params.accountId; - if (accountId && params.cachedChannel?.accounts?.[accountId]) { - return params.cachedChannel.accounts[accountId]; - } - return undefined; -} - function cachedLifecycleDiffersFromRuntime(params: { cachedAccount: ChannelHealthSummary | undefined; runtimeSnapshot: ChannelAccountSnapshot; @@ -82,16 +71,19 @@ function cachedHealthDiffersFromRuntime( continue; } const cachedChannel = cached.channels[channelId]; + const cachedAccounts = cachedChannel?.accounts; + if ( + Object.keys(cachedAccounts ?? {}).some((accountId) => !Object.hasOwn(accounts, accountId)) + ) { + return true; + } for (const [accountId, runtimeSnapshot] of Object.entries(accounts)) { if (!runtimeSnapshot) { continue; } if ( cachedLifecycleDiffersFromRuntime({ - cachedAccount: cachedAccountForRuntimeSnapshot({ - cachedChannel, - accountId, - }), + cachedAccount: cachedAccounts?.[accountId], runtimeSnapshot, }) ) { diff --git a/src/gateway/server-methods/server-methods.test.ts b/src/gateway/server-methods/server-methods.test.ts index 9d84f4d17616..e40b0f588a30 100644 --- a/src/gateway/server-methods/server-methods.test.ts +++ b/src/gateway/server-methods/server-methods.test.ts @@ -4839,6 +4839,43 @@ describe("gateway healthHandlers.health cache freshness", () => { }); expect(respond).toHaveBeenCalledWith(true, fresh, undefined); }); + + it("refreshes cached health after hot reload removes a runtime account", async () => { + const current = createSingleChannelHealthSnapshot({ + channelId: "discord", + label: "Discord", + running: true, + connected: true, + }); + const cached = { + ...current, + channels: { + discord: { + ...current.channels.discord, + accounts: { + ...current.channels.discord.accounts, + work: channelHealthAccount({ accountId: "work", running: true, connected: true }), + }, + }, + }, + }; + const { respond, refreshHealthSnapshot } = await requestHealthSnapshot({ + cached, + fresh: current, + runtimeSnapshot: { + channels: {}, + channelAccounts: { + discord: { default: { accountId: "default", running: true, connected: true } }, + }, + }, + }); + + expect(refreshHealthSnapshot).toHaveBeenCalledWith({ + probe: false, + includeSensitive: false, + }); + expect(respond).toHaveBeenCalledWith(true, current, undefined); + }); }); describe("logs.tail", () => {