v0.3.0, persistent polling update.
This commit is contained in:
54
CHANGELOG.md
54
CHANGELOG.md
@@ -5,6 +5,59 @@ All notable changes to SLMM (Sound Level Meter Manager) will be documented in th
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [0.3.0] - 2026-02-17
|
||||
|
||||
### Added
|
||||
|
||||
#### Persistent TCP Connection Pool
|
||||
- **Connection reuse** - TCP connections are cached per device and reused across commands, eliminating repeated TCP handshakes over cellular modems
|
||||
- **OS-level TCP keepalive** - Configurable keepalive probes keep cellular NAT tables alive and detect dead connections early (default: probe after 15s idle, every 10s, 3 failures = dead)
|
||||
- **Transparent retry** - If a cached connection goes stale, the system automatically retries with a fresh connection so failures are never visible to the caller
|
||||
- **Stale connection detection** - Multi-layer detection via idle TTL, max age, transport state, and reader EOF checks
|
||||
- **Background cleanup** - Periodic task (every 30s) evicts expired connections from the pool
|
||||
- **Master switch** - Set `TCP_PERSISTENT_ENABLED=false` to revert to per-request connection behavior
|
||||
|
||||
#### Connection Pool Diagnostics
|
||||
- `GET /api/nl43/_connections/status` - View pool configuration, active connections, age/idle times, and keepalive settings
|
||||
- `POST /api/nl43/_connections/flush` - Force-close all cached connections (useful for debugging)
|
||||
- **Connections tab on roster page** - Live UI showing pool config, active connections with age/idle/alive status, auto-refreshes every 5s, and flush button
|
||||
|
||||
#### Environment Variables
|
||||
- `TCP_PERSISTENT_ENABLED` (default: `true`) - Master switch for persistent connections
|
||||
- `TCP_IDLE_TTL` (default: `300`) - Close idle connections after N seconds
|
||||
- `TCP_MAX_AGE` (default: `1800`) - Force reconnect after N seconds
|
||||
- `TCP_KEEPALIVE_IDLE` (default: `15`) - Seconds idle before keepalive probes start
|
||||
- `TCP_KEEPALIVE_INTERVAL` (default: `10`) - Seconds between keepalive probes
|
||||
- `TCP_KEEPALIVE_COUNT` (default: `3`) - Failed probes before declaring connection dead
|
||||
|
||||
### Changed
|
||||
- **Health check endpoint** (`/health/devices`) - Now uses connection pool instead of opening throwaway TCP connections; checks for existing live connections first (zero-cost), only opens new connection through pool if needed
|
||||
- **Diagnostics endpoint** - Removed separate port 443 modem check (extra handshake waste); TCP reachability test now uses connection pool
|
||||
- **DRD streaming** - Streaming connections now get TCP keepalive options set; cached connections are evicted before opening dedicated streaming socket
|
||||
- **Default timeouts tuned for cellular** - Idle TTL raised to 300s (5 min), max age raised to 1800s (30 min) to survive typical polling intervals over cellular links
|
||||
|
||||
### Technical Details
|
||||
|
||||
#### Architecture
|
||||
- `ConnectionPool` class in `services.py` manages a single cached connection per device key (NL-43 only supports one TCP connection at a time)
|
||||
- Uses existing per-device asyncio locks and rate limiting — no changes to concurrency model
|
||||
- Pool is a module-level singleton initialized from environment variables at import time
|
||||
- Lifecycle managed via FastAPI lifespan: cleanup task starts on startup, all connections closed on shutdown
|
||||
- `_send_command_unlocked()` refactored to use acquire/release/discard pattern with single-retry fallback
|
||||
- Command parsing extracted to `_execute_command()` method for reuse between primary and retry paths
|
||||
|
||||
#### Cellular Modem Optimizations
|
||||
- Keepalive probes at 15s prevent cellular NAT tables from expiring (typically 30-60s timeout)
|
||||
- 300s idle TTL ensures connections survive between polling cycles (default 60s interval)
|
||||
- 1800s max age allows a single socket to serve ~30 minutes of polling before forced reconnect
|
||||
- Health checks and diagnostics produce zero additional TCP handshakes when a pooled connection exists
|
||||
- Stale `$` prompt bytes drained from idle connections before command reuse
|
||||
|
||||
### Breaking Changes
|
||||
None. This release is fully backward-compatible with v0.2.x. Set `TCP_PERSISTENT_ENABLED=false` for identical behavior to previous versions.
|
||||
|
||||
---
|
||||
|
||||
## [0.2.1] - 2026-01-23
|
||||
|
||||
### Added
|
||||
@@ -146,6 +199,7 @@ None. This release is fully backward-compatible with v0.1.x. All existing endpoi
|
||||
|
||||
## Version History Summary
|
||||
|
||||
- **v0.3.0** (2026-02-17) - Persistent TCP connections with keepalive for cellular modem reliability
|
||||
- **v0.2.1** (2026-01-23) - Roster management, scheduler hooks, FTP logging, doc cleanup
|
||||
- **v0.2.0** (2026-01-15) - Background Polling System
|
||||
- **v0.1.0** (2025-12-XX) - Initial Release
|
||||
|
||||
Reference in New Issue
Block a user