fix(telegram): stop local listener and bot on retry loop non-recoverable error (#100863)

* fix(telegram): stop local listener and bot on retry loop non-recoverable error

* fix(telegram): reuse webhook shutdown on setup failure

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
This commit is contained in:
machine3at
2026-07-06 21:39:34 +05:30
committed by GitHub
parent 5d3044f883
commit 1021784c85
2 changed files with 46 additions and 14 deletions
+44
View File
@@ -632,6 +632,50 @@ describe("startTelegramWebhook", () => {
expectMockMessageContains(runtimeError, "telegram setWebhook failed: unauthorized");
});
it("stops local listener and bot when retry loop encounters a non-recoverable error", async () => {
const runtimeError = vi.fn();
const setStatus = vi.fn();
const unauthorizedError = Object.assign(new Error("unauthorized"), { error_code: 401 });
setWebhookSpy
.mockRejectedValueOnce(new TypeError("fetch failed"))
.mockRejectedValueOnce(unauthorizedError);
const started = await startTelegramWebhook({
token: TELEGRAM_TOKEN,
port: 0,
secret: TELEGRAM_SECRET,
path: TELEGRAM_WEBHOOK_PATH,
spoolDir: requireWebhookSpoolDir(),
runtime: { log: vi.fn(), error: runtimeError, exit: vi.fn() },
setStatus,
webhookRegistrationRetryPolicy: {
initialMs: 0,
maxMs: 0,
factor: 1,
jitter: 0,
},
});
try {
await vi.waitFor(() => {
expect(started.server.listening).toBe(false);
expect(stopSpy).toHaveBeenCalledTimes(1);
expect(transportCloseSpies[0]).toHaveBeenCalledTimes(1);
});
expect(setStatus).toHaveBeenLastCalledWith({ mode: "webhook", connected: false });
expectMockMessageContains(
runtimeError,
"telegram setWebhook retry stopped after non-recoverable error",
);
await started.stop();
expect(stopSpy).toHaveBeenCalledTimes(1);
expect(transportCloseSpies[0]).toHaveBeenCalledTimes(1);
} finally {
await started.stop();
}
});
it("retries transient getMe startup init failures before starting the account", async () => {
const runtimeLog = vi.fn();
initSpy.mockRejectedValueOnce(new TypeError("fetch failed")).mockResolvedValueOnce(undefined);
+2 -14
View File
@@ -1050,25 +1050,13 @@ export async function startTelegramWebhook(opts: {
runtime.error?.(
`telegram setWebhook retry stopped after non-recoverable error: ${formatErrorMessage(err)}`,
);
await shutdown();
return;
}
}
attempt += 1;
}
};
const closeAfterStartupFailure = async () => {
shutDown = true;
if (drainTimer) {
clearInterval(drainTimer);
}
server.close();
await bot.stop();
await closeTransportOnce();
status.noteWebhookStop();
if (diagnosticsEnabled) {
stopDiagnosticHeartbeat();
}
};
runtime.log?.(`webhook local listener on http://${host}:${boundPort}${path}`);
@@ -1077,7 +1065,7 @@ export async function startTelegramWebhook(opts: {
await advertiseWebhook();
} catch (err) {
if (!shouldRetryWebhookRegistration(err)) {
await closeAfterStartupFailure();
await shutdown();
throw err;
}
void retryWebhookRegistration(1);