---
phase: 01-telegram-thread-leak
plan: 01
subsystem: logging
tags: [threading, threadpool, telegram, resilience, pydantic-settings]

requires: []
provides:
  - "Bounded ThreadPoolExecutor(max_workers=2) for Telegram log sink"
  - "Configurable log_sink_timeout_s (3s default) via NetworkConfig"
  - "Optional timeout parameter on send_telegram() (backward-compatible)"
affects: [02-kintsugi-rest-ch-connection]

tech-stack:
  added: []
  patterns: ["Module-level lazy ThreadPoolExecutor for fire-and-forget I/O"]

key-files:
  created:
    - tests/test_telegram_log_sink.py
  modified:
    - python/opendeviationbar/logging.py
    - python/opendeviationbar/config/network.py
    - python/opendeviationbar/notify/telegram.py

key-decisions:
  - "ThreadPoolExecutor over queue.Queue: simpler, 2-thread cap sufficient, no new dependencies"
  - "Lazy executor initialization via _get_telegram_log_executor() to avoid import-time side effects"
  - "Added timeout param to send_telegram() rather than calling requests.post directly in _send()"

patterns-established:
  - "Module-level lazy ThreadPoolExecutor for bounded fire-and-forget I/O tasks"
  - "Separate timeout config for log sink vs direct notification calls"

requirements-completed: [STAB-01, STAB-02]

duration: 2min
completed: 2026-03-20
---

# Phase 1 Plan 1: Telegram Thread Leak Fix Summary

**Bounded ThreadPoolExecutor(max_workers=2) replaces unbounded threading.Thread in Telegram log sink, with dedicated 3s timeout to prevent thread exhaustion during kintsugi batch repairs**

## Performance

- **Duration:** 2 min
- **Started:** 2026-03-20T08:09:53Z
- **Completed:** 2026-03-20T08:12:28Z
- **Tasks:** 1
- **Files modified:** 4

## Accomplishments

- Replaced unbounded `threading.Thread` fire-and-forget with `ThreadPoolExecutor(max_workers=2)` in `_TelegramLogSink`
- Added `log_sink_timeout_s=3` to `NetworkConfig` (separate from 10s `notification_timeout_s`)
- Added backward-compatible `timeout` parameter to `send_telegram()`
- All 4 regression tests pass: bounded pool, no Thread usage, error resilience, config validation

## Task Commits

Each task was committed atomically:

1. **Task 1 (RED): Failing tests for bounded thread pool** - `b7896f5` (test)
2. **Task 1 (GREEN): Implement bounded ThreadPoolExecutor + log sink timeout** - `e3237c7` (feat)

_TDD task: RED (failing tests) then GREEN (implementation)_

## Files Created/Modified

- `python/opendeviationbar/logging.py` - Replaced `threading.Thread` with `ThreadPoolExecutor(max_workers=2)`, lazy-init via `_get_telegram_log_executor()`
- `python/opendeviationbar/config/network.py` - Added `log_sink_timeout_s: int = 3` field
- `python/opendeviationbar/notify/telegram.py` - Added optional `timeout` kwarg to `send_telegram()`, uses `effective_timeout` pattern
- `tests/test_telegram_log_sink.py` - 4 tests: bounded pool, source grep, error resilience, config default

## Decisions Made

- Used `ThreadPoolExecutor` over `queue.Queue`: simpler API, 2-thread cap sufficient, no new dependencies needed
- Lazy executor initialization via `_get_telegram_log_executor()` avoids import-time side effects
- Added `timeout` param to `send_telegram()` rather than bypassing it in `_send()` -- cleaner, backward-compatible

## Deviations from Plan

None - plan executed exactly as written.

## Issues Encountered

None.

## User Setup Required

None - no external service configuration required.

## Next Phase Readiness

- Thread exhaustion fix is fully self-contained; no downstream changes needed
- Phase 2 (kintsugi REST + CH connection) can proceed independently

---

_Phase: 01-telegram-thread-leak_
_Completed: 2026-03-20_
