← Back to PRs

#13178: fix: dedup mapped hook dispatches to prevent Gmail Pub/Sub retries

by striking open 2026-02-10 05:48 View on GitHub →
gateway stale
## Summary - Add a TTL-based dedup cache (5 min, 500 entries) to the hooks request handler - When a mapped hook resolves with a session key that was already seen within TTL, return `200 {ok: true, duplicate: true}` instead of dispatching a new agent run - Prevents at-least-once delivery systems like Gmail Pub/Sub from triggering duplicate agent runs for the same email notification ## Root Cause Google Pub/Sub uses at-least-once delivery — the same notification can arrive multiple times. The hook handler in `server-http.ts` dispatched `dispatchAgentHook()` for every matching request without checking if that exact session key was already processed. The Gmail preset uses `hook:gmail:{{messages[0].id}}` as the session key, providing a natural dedup key. ## Changes - `src/gateway/server-http.ts` — added `createDedupeCache` import and dedup check before mapped hook dispatch (+13 lines) - `src/gateway/server-http-hooks-dedupe.test.ts` — 3 tests covering dispatch, dedup, and different IDs (new file) ## Test plan - [x] `pnpm vitest run src/gateway/server-http-hooks-dedupe.test.ts` — 3/3 passing - [x] `pnpm vitest run src/gateway/hooks-mapping.test.ts` — 7/7 passing (no regression) - [x] `pnpm build` — clean - [x] `pnpm check` — lint + format clean 🤖 Generated with [Claude Code](https://claude.com/claude-code) <!-- greptile_comment --> <h2>Greptile Overview</h2> <h3>Greptile Summary</h3> This PR adds a TTL-based in-memory dedupe cache to the gateway hooks HTTP handler so mapped hook dispatches (not `/hooks/agent`) are suppressed when the same `sessionKey` repeats within a 5 minute window. It returns `200 { ok: true, duplicate: true }` for duplicates instead of dispatching a new agent run, and includes a new Vitest file covering first-dispatch vs duplicate vs different IDs for the Gmail preset mapping. The change is localized to `createHooksRequestHandler` in `src/gateway/server-http.ts`, leveraging a shared `createDedupeCache` utility from `src/infra/dedupe.ts`, and it interacts with the existing hook mapping system (`applyHookMappings` / Gmail preset `sessionKey`). <h3>Confidence Score: 3/5</h3> - This PR is moderately safe to merge, but the dedupe flow can drop events if dispatch fails after marking a key as seen. - The core change is small and covered by tests, but the current `check()`-then-dispatch ordering means a transient dispatch failure can cause subsequent retries to be treated as duplicates (no agent run), which is a correctness issue for at-least-once delivery sources. - src/gateway/server-http.ts <!-- greptile_other_comments_section --> <sub>(3/5) Reply to the agent's comments like "Can you suggest a fix for this @greptileai?" or ask follow-up questions!</sub> <!-- /greptile_comment -->

Most Similar PRs