Skip to content

Commit ff62705

Browse files
MonkeyLeeTmcaxtr
andauthored
fix(whatsapp): reset watchdog timeout after reconnect (#60007)
Merged via squash. Prepared head SHA: 64223e5 Co-authored-by: MonkeyLeeT <6754057+MonkeyLeeT@users.noreply.github.com> Co-authored-by: mcaxtr <7562095+mcaxtr@users.noreply.github.com> Reviewed-by: @mcaxtr
1 parent 306fe84 commit ff62705

3 files changed

Lines changed: 14 additions & 10 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ Docs: https://docs.openclaw.ai
9696
- Plugins/runtime: honor explicit capability allowlists during fallback speech, media-understanding, and image-generation provider loading so bundled capability plugins do not bypass restrictive `plugins.allow` config. (#52262) Thanks @PerfectPan.
9797
- Hooks/tool policy: block tool calls when a `before_tool_call` hook crashes so hook failures fail closed instead of silently allowing execution. (#59822) Thanks @pgondhi987.
9898
- Matrix/media: surface a dedicated `[matrix <kind> attachment too large]` marker for oversized inbound media instead of the generic unavailable marker, and classify size-limit failures with a typed Matrix error. (#60289) Thanks @efe-arv.
99+
- WhatsApp/watchdog: reset watchdog timeout after reconnect so quiet channels no longer enter a tight reconnect loop from stale message timestamps carried across connection runs. (#60007) Thanks @MonkeyLeeT.
99100

100101
## 2026.4.2
101102

extensions/whatsapp/src/auto-reply.web-auto-reply.connection-and-logging.e2e.test.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,7 @@ describe("web auto-reply connection", () => {
188188
}
189189
});
190190

191-
it("keeps watchdog message age across reconnects", async () => {
191+
it("gives a reconnected listener a fresh watchdog window", async () => {
192192
vi.useFakeTimers();
193193
try {
194194
const { scripted, controller, run } = await startWatchdogScenario({
@@ -203,7 +203,11 @@ describe("web auto-reply connection", () => {
203203
{ timeout: 250, interval: 2 },
204204
);
205205

206-
await vi.advanceTimersByTimeAsync(200);
206+
await vi.advanceTimersByTimeAsync(20);
207+
await Promise.resolve();
208+
expect(scripted.getListenerCount()).toBe(2);
209+
210+
await vi.advanceTimersByTimeAsync(20);
207211
await Promise.resolve();
208212
await vi.waitFor(
209213
() => {

extensions/whatsapp/src/auto-reply/monitor.ts

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -50,13 +50,13 @@ type ActiveConnectionRun = {
5050
backgroundTasks: Set<Promise<unknown>>;
5151
};
5252

53-
function createActiveConnectionRun(lastInboundAt: number | null): ActiveConnectionRun {
53+
function createActiveConnectionRun(): ActiveConnectionRun {
5454
return {
5555
connectionId: newConnectionId(),
5656
startedAt: Date.now(),
5757
heartbeat: null,
5858
watchdogTimer: null,
59-
lastInboundAt,
59+
lastInboundAt: null,
6060
handledMessages: 0,
6161
unregisterUnhandled: null,
6262
backgroundTasks: new Set<Promise<unknown>>(),
@@ -171,7 +171,7 @@ export async function monitorWebChannel(
171171
break;
172172
}
173173

174-
const active = createActiveConnectionRun(status.lastInboundAt ?? status.lastMessageAt ?? null);
174+
const active = createActiveConnectionRun();
175175

176176
// Watchdog to detect stuck message processing (e.g., event emitter died).
177177
// Tuning overrides are test-oriented; production defaults remain unchanged.
@@ -306,10 +306,9 @@ export async function monitorWebChannel(
306306
}, heartbeatSeconds * 1000);
307307

308308
active.watchdogTimer = setInterval(() => {
309-
if (!active.lastInboundAt) {
310-
return;
311-
}
312-
const timeSinceLastMessage = Date.now() - active.lastInboundAt;
309+
// A reconnect should get a fresh watchdog window even before the next inbound arrives.
310+
const watchdogBaselineAt = active.lastInboundAt ?? active.startedAt;
311+
const timeSinceLastMessage = Date.now() - watchdogBaselineAt;
313312
if (timeSinceLastMessage <= MESSAGE_TIMEOUT_MS) {
314313
return;
315314
}
@@ -319,7 +318,7 @@ export async function monitorWebChannel(
319318
{
320319
connectionId: active.connectionId,
321320
minutesSinceLastMessage,
322-
lastInboundAt: new Date(active.lastInboundAt),
321+
lastInboundAt: active.lastInboundAt ? new Date(active.lastInboundAt) : null,
323322
messagesHandled: active.handledMessages,
324323
},
325324
"Message timeout detected - forcing reconnect",

0 commit comments

Comments
 (0)