← Back to PRs

#9172: Fix: Add rate limiting to boot-md hook to prevent spam during rapid restarts

by vishaltandale00 open 2026-02-04 23:43 View on GitHub →
stale
## Summary Fixes issue #9167 where the boot-md hook fires multiple times in rapid succession during gateway startup, causing duplicate messages to be sent. ## Problem The `boot-md` hook was firing 8-9 times within ~30 seconds when the gateway restarted frequently. Each execution of BOOT.md resulted in duplicate messages being sent to channels, spamming users. **Evidence from production:** ``` 18:16:12 -> First boot check 18:16:25 -> Second boot check (13s later) 22:01:01 -> Boot check 22:01:13 -> Again (12s later) 22:01:21 -> Again (8s) 22:01:30 -> Again (9s) 22:02:23 -> Again 22:02:41 -> Again 22:06:17 -> Again 22:06:25 -> Again ``` ## Root Cause Each gateway restart (due to config changes, crashes, or external restarts) triggers a new `gateway:startup` event, which causes the boot-md hook to execute BOOT.md again. The function is named `runBootOnce` but it actually runs once *per gateway startup*, not once *per session*. ## Solution Added **60-second rate limiting** to the boot-md hook handler. The handler now tracks the last execution timestamp and skips subsequent triggers within the rate limit window. ### Changes Made 1. **Rate limiting logic** (`src/hooks/bundled/boot-md/handler.ts`): - Track last boot time in module-scoped variable - Skip execution if called within 60 seconds of previous execution - Only affects rapid restart scenarios - normal use unaffected 2. **Comprehensive test suite** (`src/hooks/bundled/boot-md/handler.test.ts`): - Verifies rate limiting behavior - Tests edge cases (missing config, wrong event type, etc.) - Ensures proper execution after rate limit expires ## Impact ✅ **Prevents spam:** BOOT.md executes at most once per minute, even during rapid restarts ✅ **No config changes:** Works automatically with existing setups ✅ **Minimal overhead:** Single timestamp check per trigger ✅ **Backward compatible:** Normal startup behavior unchanged ## Test Plan - [x] Unit tests pass (rate limiting verification) - [ ] Manual testing: Restart gateway multiple times rapidly - [ ] Verify only one boot message is sent within 60 seconds - [ ] Verify boot message IS sent after 60 seconds ## Alternative Considered The issue reporter suggested making BOOT.md itself idempotent by checking timestamps. While that's a valid workaround, fixing it in the hook handler is better because: - Centralizes the logic (don't require every user to implement this) - More reliable (doesn't depend on filesystem state) - Cleaner (BOOT.md remains simple and declarative) --- 🤖 Generated with [Claude Code](https://claude.com/claude-code) <!-- greptile_comment --> <h2>Greptile Overview</h2> <h3>Greptile Summary</h3> This PR adds a 60s rate limiter to the bundled `boot-md` hook handler so BOOT.md won’t run repeatedly during rapid gateway restarts, and introduces a new Vitest suite to validate the handler’s behavior on `gateway:startup`. The handler change is a simple module-scoped `lastBootTime` timestamp check before calling `runBootOnce`, and the test suite covers non-gateway events, missing context, and the intended “only once per minute” behavior. <h3>Confidence Score: 2/5</h3> - This PR should not be merged until the new tests are made deterministic and isolated. - The production change is small, but the new test suite is order-dependent due to module-scoped `lastBootTime` persisting across test cases, and it relies on fake timers without explicitly controlling `Date.now()`, making rate-limit assertions flaky across environments/configs. - src/hooks/bundled/boot-md/handler.test.ts <!-- greptile_other_comments_section --> <!-- /greptile_comment -->

Most Similar PRs