mirror of
https://github.com/openclaw/openclaw.git
synced 2026-03-30 08:51:40 +00:00
fix: clear telegram polling cleanup timers
This commit is contained in:
@@ -123,6 +123,7 @@ Docs: https://docs.openclaw.ai
|
||||
- Agents/fallback cooldown probing: cap cooldown-bypass probing to one attempt per provider per fallback run so multi-model same-provider cooldown chains can continue to cross-provider fallbacks instead of repeatedly stalling on duplicate cooldown probes. (#41711) Thanks @cgdusek.
|
||||
- Telegram/direct delivery: bridge direct delivery sends to internal `message:sent` hooks so internal hook listeners observe successful Telegram deliveries. (#40185) Thanks @vincentkoc.
|
||||
- Dependencies: refresh workspace dependencies except the pinned Carbon package, and harden ACP session-config writes against non-string SDK values so newer ACP clients fail fast instead of tripping type/runtime mismatches.
|
||||
- Telegram/polling restarts: clear bounded cleanup timeout handles after `runner.stop()` and `bot.stop()` settle so stall recovery no longer leaves stray 15-second timers behind on clean shutdown. (#43188) thanks @kyohwang.
|
||||
|
||||
## 2026.3.8
|
||||
|
||||
|
||||
@@ -398,6 +398,20 @@ describe("monitorTelegramProvider (grammY)", () => {
|
||||
expect(createdBotStops[0]).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it("clears bounded cleanup timers after a clean stop", async () => {
|
||||
vi.useFakeTimers();
|
||||
try {
|
||||
const abort = new AbortController();
|
||||
mockRunOnceAndAbort(abort);
|
||||
|
||||
await monitorTelegramProvider({ token: "tok", abortSignal: abort.signal });
|
||||
|
||||
expect(vi.getTimerCount()).toBe(0);
|
||||
} finally {
|
||||
vi.useRealTimers();
|
||||
}
|
||||
});
|
||||
|
||||
it("surfaces non-recoverable errors", async () => {
|
||||
runSpy.mockImplementationOnce(() =>
|
||||
makeRunnerStub({
|
||||
|
||||
@@ -17,6 +17,23 @@ const POLL_STALL_THRESHOLD_MS = 90_000;
|
||||
const POLL_WATCHDOG_INTERVAL_MS = 30_000;
|
||||
const POLL_STOP_GRACE_MS = 15_000;
|
||||
|
||||
const waitForGracefulStop = async (stop: () => Promise<void>) => {
|
||||
let timer: ReturnType<typeof setTimeout> | undefined;
|
||||
try {
|
||||
await Promise.race([
|
||||
stop(),
|
||||
new Promise<void>((resolve) => {
|
||||
timer = setTimeout(resolve, POLL_STOP_GRACE_MS);
|
||||
timer.unref?.();
|
||||
}),
|
||||
]);
|
||||
} finally {
|
||||
if (timer) {
|
||||
clearTimeout(timer);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
type TelegramBot = ReturnType<typeof createTelegramBot>;
|
||||
|
||||
type TelegramPollingSessionOpts = {
|
||||
@@ -271,14 +288,8 @@ export class TelegramPollingSession {
|
||||
clearTimeout(forceCycleTimer);
|
||||
}
|
||||
this.opts.abortSignal?.removeEventListener("abort", stopOnAbort);
|
||||
await Promise.race([
|
||||
stopRunner(),
|
||||
new Promise<void>((resolve) => setTimeout(resolve, POLL_STOP_GRACE_MS)),
|
||||
]);
|
||||
await Promise.race([
|
||||
stopBot(),
|
||||
new Promise<void>((resolve) => setTimeout(resolve, POLL_STOP_GRACE_MS)),
|
||||
]);
|
||||
await waitForGracefulStop(stopRunner);
|
||||
await waitForGracefulStop(stopBot);
|
||||
this.#activeRunner = undefined;
|
||||
if (this.#activeFetchAbort === fetchAbortController) {
|
||||
this.#activeFetchAbort = undefined;
|
||||
|
||||
Reference in New Issue
Block a user