fix(zalo): make poll error backoff abort-aware

This commit is contained in:
NIO
2026-07-14 08:48:26 +08:00
committed by Peter Steinberger
parent d87aea2b83
commit cc76dc1d8f
2 changed files with 35 additions and 4 deletions
@@ -72,6 +72,8 @@ async function startLifecycleMonitor(
describe("monitorZaloProvider lifecycle", () => {
afterEach(() => {
vi.clearAllMocks();
getUpdatesMock.mockReset();
getUpdatesMock.mockImplementation(() => new Promise(() => {}));
setActivePluginRegistry(createEmptyPluginRegistry());
});
@@ -97,6 +99,36 @@ describe("monitorZaloProvider lifecycle", () => {
expect(runtime.log).toHaveBeenCalledWith("[default] Zalo provider stopped mode=polling");
});
it("ends poll error backoff immediately when abort fires", async () => {
getUpdatesMock.mockReset();
getUpdatesMock.mockRejectedValue(new Error("zalo poll transport failed"));
let settled = false;
const { abort, runtime, run } = await startLifecycleMonitor();
const monitoredRun = run.then(() => {
settled = true;
});
await vi.waitFor(() =>
expect(runtime.error).toHaveBeenCalledWith(expect.stringContaining("Zalo polling error:")),
);
expect(runtime.error).toHaveBeenCalledWith(
expect.stringContaining("zalo poll transport failed"),
);
expect(settled).toBe(false);
// Abort during the 5s error backoff; sleepWithAbort must end immediately
// instead of waiting out the full setTimeout.
const started = Date.now();
abort.abort();
await monitoredRun;
const elapsedMs = Date.now() - started;
expect(settled).toBe(true);
expect(elapsedMs).toBeLessThan(1_000);
expect(runtime.log).toHaveBeenCalledWith("[default] Zalo provider stopped mode=polling");
});
it("deletes an existing webhook before polling", async () => {
getWebhookInfoMock.mockResolvedValueOnce({
ok: true,
+3 -4
View File
@@ -12,7 +12,7 @@ import {
deliverTextOrMediaReply,
type OutboundReplyPayload,
} from "openclaw/plugin-sdk/reply-payload";
import { waitForAbortSignal } from "openclaw/plugin-sdk/runtime-env";
import { sleepWithAbort, waitForAbortSignal } from "openclaw/plugin-sdk/runtime-env";
import {
resolveDefaultGroupPolicy,
warnMissingProviderGroupPolicyFallbackOnce,
@@ -281,9 +281,8 @@ function startPollingLoop(params: ZaloPollingLoopParams) {
// no updates
} else if (!isStopped() && !abortSignal.aborted) {
runtime.error?.(`[${account.accountId}] Zalo polling error: ${formatZaloError(err)}`);
await new Promise((resolve) => {
setTimeout(resolve, 5000);
});
// Abort-aware backoff; bottom poll reschedule already checks stopped/aborted.
await sleepWithAbort(5000, abortSignal).catch(() => undefined);
}
}