ConnectionMonitor.gather_cluster_stats was calling :rpc.call(Node.self())
which GenServer.call'd back into itself while blocked in handle_info,
causing a 5-second deadlock timeout every 30 seconds. Fixed by computing
local stats directly from state.
LeaderElection never verified that a leader still held the :global
registration. After :global conflict resolution (two isolated nodes
merging), the loser was silently unregistered but stayed is_leader: true
forever, causing both pods to connect to APRS-IS with the same callsign
in a reconnect loop. Fixed by adding verify_leadership/1 to
check_leadership which detects lost registrations and steps down.
- Add missing env vars to migration init container (PHX_HOST, PORT,
APRS_PORT, APRS_CALLSIGN, APRS_PASSCODE) so runtime.exs config
provider doesn't fail due to Kubernetes service discovery injecting
APRS_PORT as a full URL
- Guard ConnectionMonitor.accepting_connections?/0 with Process.whereis
to avoid crashing when the GenServer isn't started (e.g. cluster
enabled but no libcluster topologies configured)
Extract nested logic into helper functions to improve readability:
- regex_cache.ex: Extract compile_and_cache/1 for regex compilation and caching
- connection_monitor.ex: Extract calculate_scheduler_utilization/1 for CPU stat calculation
- device_identification.ex: Extract fetch_devices_from_url/0 for HTTP request handling
Co-Authored-By: Graham <noreply@anthropic.com>
- Fix leader election guard test for :undefined pid
- Fix cpu_sup.util() pattern matching to handle numeric return
- Fix encoding_utils to always return explicit nil when needed
- Remove unused finite_float? function
- Fix signal handler to match :ok return from :os.set_signal/2
- Remove redundant catch-all pattern in database metrics
- Fix Gridsquare pattern matching in info_live template
- Remove unnecessary nil check for calculate_course result
- Fix get_packet_received_at to not check for nil (always returns DateTime)
- Remove redundant catch-all pattern in weather format_weather_value
- Fix query builder to use from(p in Packet) instead of bare Packet atom
Reduced dialyzer errors from 49 to 6. Remaining warnings are mostly
false positives from template compilation and overloaded function specs.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
Implements automatic connection draining to balance load across cluster nodes:
- ConnectionMonitor tracks CPU usage and connection counts across nodes
- Triggers draining when node is overloaded (>70% CPU or 2x avg connections)
- LiveViews gracefully disconnect and reconnect to less loaded nodes
- Helps prevent single pod from handling all WebSocket connections
Also fixes Mic-E packet parsing to properly extract altitude data and
remove telemetry suffixes from comments.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>