Three-tier routing cache (ESL global -> file -> HTTP) eliminates HTTP
from call path for 2500-5000 concurrent calls. Lua reads cached route
in ~0.1us instead of blocking on api:execute('curl', ...).
Engine fixes:
- recalcBestLocked now skips stale nodes (was 5 min bug -> now ~10-15s)
- PickNodeForCall action_type='node' checks staleness for consistency
- onMetric callback pushes cache on every metric (no ticker delay)
Config:
- stale_threshold_sec default 20 -> 10 (industry standard)
- contrib/ included in Makefile deploy target
- route.lua paths updated for /opt/pulse-lets-go
Routing rules:
- RouteRule model: 3 match fields (caller_id, dest, ingress_trunk regex),
3 action types (node/pool/auto), time-based (days of week, time range)
- Engine router.go: CompiledRule with pre-compiled regex,
PickNodeForCall with cascade (dead node → next rule), pickNodeFromPool
- Separate sync.RWMutex for Router — zero contention admin vs traffic
- Validate-before-save pattern: engine validates before JSON save
- Graceful degradation: corrupted rules skipped, no rules → PickNode()
Persistence:
- data/routing.json with atomic save (tmp→rename), config.Manager
- Auto-created empty on first start
API (admin only):
- GET/POST/PUT/DELETE /api/routing/rules
- PUT /api/routing/rules/:id/toggle
- PUT /api/routing/rules/reorder
Integration:
- /api/route now uses PickNodeForCall with caller_id/dest/ingress_trunk
query params (already sent by route.lua)
- RouteResponse includes matched_rule field for debugging
- Main.go loads routing rules on startup with graceful fallback
Web UI:
- /routing page: table with priority arrows, inline edit, create form,
regex test tool, toggle, delete, action badges, hits counter
Tests:
- 28 tests: matchRule, time matching, PickNodeForCall cascade,
pool scoring, validation, hit counting, compilation
* findWebDir: CWD and project root checked before binary-adjacent path,
so dev always serves fresh web/build/ over stale bin/web/build/
* build-go: auto-copies web/build/ to bin/web/ before Go compile
* build-prod: same auto-copy for production builds
* Proper refresh of frontend static on every make build
- SIPGateway field in NodeMetric model
- HasNode() engine method
- OnNewNode callback in NATS subscriber
- Auto-create balance trunk from new node metric
- BroadcastGatewayEvent on WS hub
- Gateway status indicators in trunks UI (green/red/gray)
- SPA fallback for frontend routing