fix(whatsapp): report transport activity so stale-socket health detection works

This commit is contained in:
Sathvik-1007
2026-04-27 11:58:09 +05:30
committed by Marcus Castro
parent 8edb99f0e3
commit cd2e3e0444
3 changed files with 60 additions and 1 deletions

View File

@@ -0,0 +1,53 @@
import { describe, expect, it } from "vitest";
import { createWebChannelStatusController } from "./monitor-state.js";
describe("createWebChannelStatusController", () => {
it("sets lastTransportActivityAt on noteConnected", () => {
const patches: Record<string, unknown>[] = [];
const controller = createWebChannelStatusController((s) => patches.push({ ...s }));
controller.noteConnected(1000);
const last = patches.at(-1)!;
expect(last.connected).toBe(true);
expect(last.lastTransportActivityAt).toBe(1000);
});
it("updates lastTransportActivityAt on noteInbound", () => {
const patches: Record<string, unknown>[] = [];
const controller = createWebChannelStatusController((s) => patches.push({ ...s }));
controller.noteConnected(1000);
controller.noteInbound(2000);
const last = patches.at(-1)!;
expect(last.lastTransportActivityAt).toBe(2000);
});
it("does not set lastTransportActivityAt on noteWatchdogStale", () => {
const patches: Record<string, unknown>[] = [];
const controller = createWebChannelStatusController((s) => patches.push({ ...s }));
controller.noteConnected(1000);
controller.noteWatchdogStale(5000);
const last = patches.at(-1)!;
// Watchdog staleness should not refresh transport activity — it means
// the check loop is running but the socket itself is idle/stale.
expect(last.lastTransportActivityAt).toBe(1000);
});
it("produces snapshots that enable stale-socket health detection", () => {
const patches: Record<string, unknown>[] = [];
const controller = createWebChannelStatusController((s) => patches.push({ ...s }));
controller.noteConnected(1000);
const last = patches.at(-1)!;
// The gateway health policy checks `connected === true && lastTransportActivityAt != null`
// to decide whether to run stale-socket detection. Both must be present.
expect(last.connected).toBe(true);
expect(last.lastTransportActivityAt).not.toBeNull();
expect(typeof last.lastTransportActivityAt).toBe("number");
});
});

View File

@@ -1,4 +1,7 @@
import { createConnectedChannelStatusPatch } from "openclaw/plugin-sdk/gateway-runtime";
import {
createConnectedChannelStatusPatch,
createTransportActivityStatusPatch,
} from "openclaw/plugin-sdk/gateway-runtime";
import type { WebChannelHealthState, WebChannelStatus } from "./types.js";
function cloneStatus(status: WebChannelStatus): WebChannelStatus {
@@ -35,6 +38,7 @@ export function createWebChannelStatusController(statusSink?: (status: WebChanne
snapshot: () => status,
noteConnected(at = Date.now()) {
Object.assign(status, createConnectedChannelStatusPatch(at));
Object.assign(status, createTransportActivityStatusPatch(at));
status.lastError = null;
status.healthState = "healthy";
emit();
@@ -43,6 +47,7 @@ export function createWebChannelStatusController(statusSink?: (status: WebChanne
status.lastInboundAt = at;
status.lastMessageAt = at;
status.lastEventAt = at;
Object.assign(status, createTransportActivityStatusPatch(at));
if (status.connected) {
status.healthState = "healthy";
}

View File

@@ -27,6 +27,7 @@ export type WebChannelStatus = {
lastInboundAt?: number | null;
lastMessageAt?: number | null;
lastEventAt?: number | null;
lastTransportActivityAt?: number | null;
lastError?: string | null;
healthState?: WebChannelHealthState;
};