mirror of
https://github.com/openclaw/openclaw.git
synced 2026-03-13 19:10:39 +00:00
fix(gateway): skip heartbeat wake on deduped notifications
This commit is contained in:
@@ -357,6 +357,7 @@ describe("notifications changed events", () => {
|
||||
requestHeartbeatNowMock.mockClear();
|
||||
loadSessionEntryMock.mockClear();
|
||||
loadSessionEntryMock.mockImplementation((sessionKey: string) => buildSessionLookup(sessionKey));
|
||||
enqueueSystemEventMock.mockReturnValue(true);
|
||||
});
|
||||
|
||||
it("enqueues notifications.changed posted events", async () => {
|
||||
@@ -457,6 +458,31 @@ describe("notifications changed events", () => {
|
||||
expect(enqueueSystemEventMock).not.toHaveBeenCalled();
|
||||
expect(requestHeartbeatNowMock).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("does not wake heartbeat when notifications.changed event is deduped", async () => {
|
||||
enqueueSystemEventMock.mockReset();
|
||||
enqueueSystemEventMock.mockReturnValueOnce(true).mockReturnValueOnce(false);
|
||||
const ctx = buildCtx();
|
||||
const payload = JSON.stringify({
|
||||
change: "posted",
|
||||
key: "notif-dupe",
|
||||
packageName: "com.example.chat",
|
||||
title: "Message",
|
||||
text: "Ping from Alex",
|
||||
});
|
||||
|
||||
await handleNodeEvent(ctx, "node-n6", {
|
||||
event: "notifications.changed",
|
||||
payloadJSON: payload,
|
||||
});
|
||||
await handleNodeEvent(ctx, "node-n6", {
|
||||
event: "notifications.changed",
|
||||
payloadJSON: payload,
|
||||
});
|
||||
|
||||
expect(enqueueSystemEventMock).toHaveBeenCalledTimes(2);
|
||||
expect(requestHeartbeatNowMock).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe("agent request events", () => {
|
||||
|
||||
@@ -485,8 +485,13 @@ export const handleNodeEvent = async (ctx: NodeEventContext, nodeId: string, evt
|
||||
}
|
||||
}
|
||||
|
||||
enqueueSystemEvent(summary, { sessionKey, contextKey: `notification:${key}` });
|
||||
requestHeartbeatNow({ reason: "notifications-event", sessionKey });
|
||||
const queued = enqueueSystemEvent(summary, {
|
||||
sessionKey,
|
||||
contextKey: `notification:${key}`,
|
||||
});
|
||||
if (queued) {
|
||||
requestHeartbeatNow({ reason: "notifications-event", sessionKey });
|
||||
}
|
||||
return;
|
||||
}
|
||||
case "chat.subscribe": {
|
||||
|
||||
@@ -46,6 +46,14 @@ describe("system events (session routing)", () => {
|
||||
it("requires an explicit session key", () => {
|
||||
expect(() => enqueueSystemEvent("Node: Mac Studio", { sessionKey: " " })).toThrow("sessionKey");
|
||||
});
|
||||
|
||||
it("returns false for consecutive duplicate events", () => {
|
||||
const first = enqueueSystemEvent("Node connected", { sessionKey: "agent:main:main" });
|
||||
const second = enqueueSystemEvent("Node connected", { sessionKey: "agent:main:main" });
|
||||
|
||||
expect(first).toBe(true);
|
||||
expect(second).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("isCronSystemEvent", () => {
|
||||
|
||||
@@ -63,12 +63,12 @@ export function enqueueSystemEvent(text: string, options: SystemEventOptions) {
|
||||
})();
|
||||
const cleaned = text.trim();
|
||||
if (!cleaned) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
const normalizedContextKey = normalizeContextKey(options?.contextKey);
|
||||
entry.lastContextKey = normalizedContextKey;
|
||||
if (entry.lastText === cleaned) {
|
||||
return;
|
||||
return false;
|
||||
} // skip consecutive duplicates
|
||||
entry.lastText = cleaned;
|
||||
entry.queue.push({
|
||||
@@ -79,6 +79,7 @@ export function enqueueSystemEvent(text: string, options: SystemEventOptions) {
|
||||
if (entry.queue.length > MAX_EVENTS) {
|
||||
entry.queue.shift();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
export function drainSystemEventEntries(sessionKey: string): SystemEvent[] {
|
||||
|
||||
Reference in New Issue
Block a user