#10641: fix(gateway): deduplicate heartbeat events across instances
docs
channel: telegram
gateway
stale
Issue #10061 is about duplicate heartbeat handling when multiple gateways run behind a load balancer.
What’s wrong
With several OpenClaw Gateway instances (e.g. 3 for HA), the same Telegram webhook is delivered to every instance. Each instance treats the update as new and runs the full heartbeat flow (session_status, exec date, cron list, full AI reply). So one logical heartbeat is processed 3 times and burns about 5–10K tokens per duplicate (e.g. 2K × 3 ≈ 6K tokens in the reported logs).
Why it happens
Deduplication is per process: each instance keeps its own in-memory set of “seen” updates (e.g. by update_id). There is no shared state, so instance 2 and 3 have never seen that update_id and both process it. The report’s “timestamp-based” note is a bit off — the real issue is in-memory, per-instance dedupe, not timestamps differing.
Expected vs actual
Expected: Only one instance processes a given heartbeat message; the others skip it.
Actual: Every instance processes the same message → repeated tool calls and AI runs.
Scope
Channel: Observed on Telegram; the same pattern would affect any channel where the same webhook is sent to multiple gateways.
Environment: e.g. OpenClaw 2026.2.3-1, Node v22.22.0, 3 gateway processes (PIDs 14697, 22466, 45287).
The fix we implemented adds cross-instance inbound deduplication via an optional shared claim store (gateway.inboundDedupe with a file-backed dir or memory), so only one instance “claims” and processes each webhook; the others skip and avoid the extra token cost.
<!-- greptile_comment -->
<h2>Greptile Overview</h2>
<h3>Greptile Summary</h3>
- Adds an optional cross-instance inbound deduplication mechanism for webhook-driven channels (aimed at Telegram heartbeat updates behind HA load balancers).
- Threads an `inboundClaimStore` through gateway → channel manager → Telegram monitor/webhook → Telegram bot middleware.
- Introduces `gateway.inboundDedupe` config (memory default; optional file-backed shared directory) and docs describing HA setup.
<h3>Confidence Score: 4/5</h3>
- This PR is close to safe to merge, with one interface/behavior mismatch that should be fixed to avoid incorrect dedupe TTL semantics.
- Core wiring for cross-instance inbound claims is straightforward and limited in scope. The main concern is that the file-backed claim store currently ignores the per-call TTL parameter even though the interface exposes it, which can lead to incorrect claim expiration behavior for any callers that rely on a custom TTL.
- src/infra/inbound-claim.ts
<!-- greptile_other_comments_section -->
<sub>(4/5) You can add custom instructions or style guidelines for the agent [here](https://app.greptile.com/review/github)!</sub>
<!-- /greptile_comment -->
Most Similar PRs
#8713: feat: gateway memory monitor, install linger, docs and failover
by quratus · 2026-02-04
75.5%
#8166: fix(telegram): lifecycle fixes for duplicate messages and auto-reco...
by cheenu1092-oss · 2026-02-03
74.6%
#20420: Telegram webhook listener to use the gateway's HTTP server instead ...
by kesor · 2026-02-18
72.6%
#7719: fix(slack): thread replies with @mentions dropped in requireMention...
by SocialNerd42069 · 2026-02-03
72.6%
#12234: gateway: incident tracking, recover command, and ciao ERR_SERVER_CL...
by levineam · 2026-02-09
72.5%
#12635: Gateway: add inbound webhook dispatch framework
by jhs129 · 2026-02-09
72.0%
#15564: fix: webchat messages disappear during concurrent session activity
by Automatedcapitalist · 2026-02-13
71.9%
#6302: fix: Add timeouts to prevent indefinite hangs (issues #4954, #4956,...
by batumilove · 2026-02-01
71.6%
#16736: fix: stagger multi-account channel startup to avoid Discord rate li...
by rm289 · 2026-02-15
71.6%
#9184: Fix: Heartbeat timer not resuming after macOS sleep/wake cycle
by vishaltandale00 · 2026-02-05
71.5%