#8166: fix(telegram): lifecycle fixes for duplicate messages and auto-recovery [AI-assisted]
channel: telegram
size: M
## Summary
Fixes #8140 - Telegram Channel Issues (duplicate messages after SIGUSR1, no auto-recovery)
### Problem
1. **Duplicate messages after SIGUSR1** - Multiple Telegram provider instances could start concurrently during rapid restarts, each receiving the same updates
2. **No debouncing** - Rapid config reloads could spawn multiple instances within milliseconds
### Solution
1. **Single-instance enforcement** - Added `InstanceState` tracking with `running`, `starting`, and `lastStartAttempt` fields per accountId
2. **Debounce restarts** - 1500ms minimum delay between start attempts prevents rapid restart issues
3. **Proper cleanup** - Instance state is always cleared in the `finally` block, ensuring restarts are possible after errors
4. **Enhanced logging** - All logs now include `[telegram:${accountId}]` prefix for better debugging
### Changes
- `src/telegram/monitor.ts` - Added instance state management and debouncing
- `src/telegram/monitor.test.ts` - Added 4 new tests
### Testing
- [x] All existing tests pass
- [x] New tests added:
- "prevents duplicate instances from starting simultaneously"
- "debounces rapid start attempts"
- "allows start after debounce period"
- "clears running state on error allowing subsequent starts"
- [x] Ran `pnpm test src/telegram`
### AI Disclosure
- [x] AI-assisted (Claude via Clawdbot)
- [x] Fully tested locally
- [x] I understand what the code does
The implementation follows the existing code patterns in the codebase and addresses the community-reported issues in #8140.
<!-- greptile_comment -->
<h2>Greptile Overview</h2>
<h3>Greptile Summary</h3>
This PR adds per-`accountId` instance tracking to `src/telegram/monitor.ts` to prevent concurrent Telegram provider starts and to debounce rapid restart attempts (e.g., during SIGUSR1 reloads). It also prefixes logs with `[telegram:<accountId>]` and adds tests covering duplicate-start prevention, debounce behavior, and state cleanup on error.
The approach fits the existing monitor loop by gating provider startup before entering the polling runner/webhook startup path, and then clearing state on exit to allow future restarts.
<h3>Confidence Score: 4/5</h3>
- This PR looks safe to merge with minor lifecycle/state-ordering concerns.
- Changes are localized and covered by new tests, but there are a couple of ordering/coupling issues (early config resolution before handler registration, and state transitions relying on side effects) that could cause edge-case behavior during misconfig or future edits.
- src/telegram/monitor.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
#6463: fix(telegram): improve timeout handling and prevent channel exits
by ai-fanatic · 2026-02-01
84.7%
#3186: fix(telegram): sanitize update offset + lock polling
by daxiong888 · 2026-01-28
84.7%
#7141: fix(telegram): unify network error detection to prevent poll crashes
by hclsys · 2026-02-02
83.2%
#6447: fix(telegram): auto-restart polling when grammY runner exits silently
by AugmentAdvertise · 2026-02-01
82.8%
#10850: fix(telegram): await runner.stop() to prevent polling race conditio...
by talhaorak · 2026-02-07
82.6%
#11273: fix(telegram): prevent status command crash during thinking
by avirweb · 2026-02-07
81.4%
#7247: fix(telegram): abort stale getUpdates connections after long-poll t...
by JanderV · 2026-02-02
80.7%
#23238: fix(telegram): account named "default" silently breaks inbound polling
by anillBhoi · 2026-02-22
80.2%
#19800: fix(telegram): add INFO-level logging at inbound message drop paths
by katalabut · 2026-02-18
80.2%
#5561: fix(telegram): auto-restart on timeout + lower API timeout to 60s
by jesseproudman · 2026-01-31
80.1%