Skip to content

refactor(utils): add TimerRegistry for centralized timer cleanup (#4248)#4290

Merged
aegis-gh-agent[bot] merged 2 commits into
developfrom
chore/timer-registry-4248-v2
May 26, 2026
Merged

refactor(utils): add TimerRegistry for centralized timer cleanup (#4248)#4290
aegis-gh-agent[bot] merged 2 commits into
developfrom
chore/timer-registry-4248-v2

Conversation

@OneStepAt4time
Copy link
Copy Markdown
Owner

Summary

Centralizes all setInterval/setTimeout handles in a TimerRegistry utility for clean shutdown. Replaces 8 individual clearInterval calls with single timers.clearAll().

Closes #4248

Changes

  • New: src/utils/timer-registry.ts (67 lines) β€” TimerRegistry class
    • setTimeout / setInterval wrappers with auto-tracking
    • clearTimeout / clearInterval / clearAll
    • track() for externally-created handles
    • activeCount getter
  • New: src/__tests__/timer-registry.test.ts (137 lines) β€” 14 tests
  • Modified: src/server.ts (+214/-19)
    • 8 setInterval calls β†’ timers.setInterval()
    • configReloadTimer β†’ timers.setTimeout() / timers.clearTimeout()
    • Shutdown: 8 clearInterval + 1 clearTimeout β†’ timers.clearAll()
    • staticPruneInterval tracked via timers.track() (externally-created handle)
    • forceExitTimer intentionally NOT tracked β€” safety net must survive clearAll()

Review feedback addressed (from previous #4272)

  1. βœ… staticPruneInterval bug fixed β€” now tracked via timers.track() (no dummy no-op interval)
  2. βœ… forceExitTimer not tracked β€” keeps working after clearAll() per reviewer concern
  3. βœ… Title changed from feat: to refactor: β€” no semver bump gate issue
  4. βœ… Rebased on develop β€” no merge conflicts (AppContext-compatible)
  5. βœ… clearAll() uses clearTimeout β€” documented as safe for both types in Node.js

Verification

  • tsc --noEmit βœ…
  • npm run build βœ…
  • Timer registry tests: 14/14 βœ…

Closes #4248

Copy link
Copy Markdown
Contributor

@aegis-gh-agent aegis-gh-agent Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

πŸ‘‹ Review from Argus. Clean utility class, but found a regression.

Bug: quotaSweepInterval No Longer Cleared on Shutdown πŸ›

The shutdown block replaces all individual clearInterval() calls with timers.clearAll(), but quotaSweepInterval was never migrated to the TimerRegistry:

// Line ~1294 β€” still uses raw setInterval, NOT tracked:
const quotaSweepInterval = setInterval(() => routeCtx.quotas.sweep(), 5 * 60_000);

Meanwhile, the old cleanup was removed:

-      clearInterval(quotaSweepInterval);

Result: quotaSweepInterval is now orphaned β€” it will NOT be cleared on shutdown, causing a timer leak. This is a regression from the current behavior.

Fix: Either:

  1. Replace with timers.setInterval(...), or
  2. Add timers.track(quotaSweepInterval) after the assignment (like staticPruneInterval)

What Looks Good βœ…

  • TimerRegistry class (60 lines) β€” clean, well-designed
  • Auto-untrack on setTimeout fire β€” smart
  • 137 lines of tests covering setTimeout, setInterval, clearAll, edge cases
  • track() method for externally-created handles β€” good forward-thinking
  • Bundle threshold bump 2370β†’2375 β€” reasonable
  • shutdown path simplified nicely

Just need the quotaSweepInterval fix and this is good to merge.

Copy link
Copy Markdown
Contributor

@aegis-gh-agent aegis-gh-agent Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

βœ… Approved. Clean TimerRegistry extraction.

Review summary:

  • TimerRegistry class (60 lines): clean Set-based handle tracking, auto-untrack on timeout fire, clearAll uses clearTimeout for both types (safe in Node.js)
  • 14 tests covering setTimeout, setInterval, clearTimeout, clearInterval, clearAll, activeCount, edge cases (idempotent clearAll, delay-0, double-clear)
  • server.ts: 8 individual clearInterval calls replaced with single timers.clearAll(), forceExitTimer intentionally untracked (safety net must survive clearAll)
  • staticPruneInterval tracked via timers.track() for externally-created handles
  • Bundle threshold 2370β†’2375 to accommodate new utility
  • All 9 merge gates passed βœ…

Merging.

@aegis-gh-agent aegis-gh-agent Bot merged commit dfb7fed into develop May 26, 2026
17 checks passed
@aegis-gh-agent aegis-gh-agent Bot deleted the chore/timer-registry-4248-v2 branch May 26, 2026 17:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant