fix(gateway): keep tick broadcasts non-droppable (#65436)

* fix(gateway): keep tick broadcasts non-droppable

* Update CHANGELOG.md
This commit is contained in:
Vincent Koc
2026-04-12 16:53:34 +01:00
committed by GitHub
parent 3cf0dda22a
commit 786de3eca2
3 changed files with 21 additions and 1 deletions

View File

@@ -10,6 +10,7 @@ Docs: https://docs.openclaw.ai
- Gateway/auth: blank the shipped example gateway credential in `.env.example` and fail startup when a copied placeholder token or password is still configured, so operators cannot accidentally launch with a publicly known secret. (#64586) Thanks @navarrotech and @vincentkoc.
- Memory/active-memory+dreaming: keep active-memory recall runs on the strongest resolved channel, consume managed dreaming heartbeat events exactly once, stop dreaming from re-ingesting its own narrative transcripts, and add explicit repair/dedupe recovery flows in CLI, doctor, and the Dreams UI.
- Gateway/keepalive: stop marking WebSocket tick broadcasts as droppable so slow or backpressured clients do not self-disconnect with `tick timeout` while long-running work is still alive. (#65256) Thanks @100yenadmin and @vincentkoc.
- Matrix/mentions: keep room mention gating strict while accepting visible `@displayName` Matrix URI labels, so `requireMention` works for non-OpenClaw Matrix clients again. (#64796) Thanks @hclsys.
- Doctor: warn when on-disk agent directories still exist under `~/.openclaw/agents/<id>/agent` but the matching `agents.list[]` entries are missing from config. (#65113) Thanks @neeravmakwana.
- Telegram: route approval button callback queries onto a separate sequentializer lane so plugin approval clicks can resolve immediately instead of deadlocking behind the blocked agent turn. (#64979) Thanks @nk3750.

View File

@@ -104,6 +104,25 @@ describe("startGatewayMaintenanceTimers", () => {
stopMaintenanceTimers(timers);
});
it("broadcasts tick keepalives without dropIfSlow", async () => {
vi.useFakeTimers();
vi.setSystemTime(new Date("2026-04-12T00:00:00Z"));
const { startGatewayMaintenanceTimers } = await import("./server-maintenance.js");
const broadcast = vi.fn();
const timers = startGatewayMaintenanceTimers({
...createMaintenanceTimerDeps(),
broadcast,
});
broadcast.mockClear();
await vi.advanceTimersByTimeAsync(30_000);
expect(broadcast).toHaveBeenCalledWith("tick", { ts: Date.now() });
stopMaintenanceTimers(timers);
});
it("skips overlapping media cleanup runs", async () => {
vi.useFakeTimers();
let resolveCleanup = () => {};

View File

@@ -61,7 +61,7 @@ export function startGatewayMaintenanceTimers(params: {
// periodic keepalive
const tickInterval = setInterval(() => {
const payload = { ts: Date.now() };
params.broadcast("tick", payload, { dropIfSlow: true });
params.broadcast("tick", payload);
params.nodeSendToAllSubscribed("tick", payload);
}, TICK_INTERVAL_MS);