fix: handle alert_changed message in DashboardLive (#189)

Fixes FunctionClauseError when DashboardLive receives {:alert_changed, org_id}
message broadcast by user_auth hooks.

The user_auth module subscribes all LiveViews to the
"organization:#{org_id}:alerts" topic and broadcasts {:alert_changed, org_id}
messages when alerts are created or resolved. DashboardLive was missing a
handle_info/2 clause to handle this message format, causing crashes in
production.

Solution:
- Added handle_info/2 clause for {:alert_changed, _org_id} message
- Uses existing debounced reload pattern to update dashboard
- Added test to verify message is handled without crashing
- Updated both technical and user-facing changelogs

All tests pass. The fix follows the same pattern used in AlertLive.Index
and DeviceLive.Show.

Reviewed-on: graham/towerops-web#189
This commit is contained in:
Graham McIntire 2026-03-27 13:26:39 -05:00 committed by graham
parent a9c2f8e5e5
commit 3f08fd42b6
4 changed files with 37 additions and 0 deletions

View file

@ -1,3 +1,12 @@
2026-03-27
fix: handle alert_changed message in DashboardLive
- Fixed FunctionClauseError when DashboardLive receives {:alert_changed, org_id} message
- Added handle_info/2 clause to handle alert_changed broadcasts from user_auth hooks
- Uses existing debounced reload pattern to update dashboard when alerts change
- Added test to verify the message is handled without crashing
- All LiveViews now properly subscribed to organization:#{org_id}:alerts topic
Files: lib/towerops_web/live/dashboard_live.ex, test/towerops_web/live/dashboard_live_test.exs
2026-03-27
docs: comprehensive audit review and verification
- Verified all 47 Process.sleep instances in tests are intentional, not flaky

View file

@ -86,6 +86,11 @@ defmodule ToweropsWeb.DashboardLive do
{:noreply, schedule_debounced_dashboard_reload(socket)}
end
@impl true
def handle_info({:alert_changed, _org_id}, socket) do
{:noreply, schedule_debounced_dashboard_reload(socket)}
end
@impl true
def handle_info(:debounced_dashboard_reload, socket) do
{:noreply, load_dashboard_data(socket, socket.assigns.current_scope.organization.id)}

View file

@ -1,3 +1,7 @@
2026-03-27 — Stability Improvements
* Fixed dashboard crashes when alerts change
* Improved real-time alert updates reliability
2026-03-27 — Code Quality and Performance Improvements
* Improved code architecture by better organizing database queries
* Added database indexes to speed up array-based queries

View file

@ -357,6 +357,25 @@ defmodule ToweropsWeb.DashboardLiveTest do
html = render(view)
refute html =~ "Device went down"
end
test "handles alert_changed broadcasts without crashing", %{
conn: conn,
organization: organization
} do
{:ok, view, _html} = live(conn, ~p"/dashboard")
# Broadcast alert_changed message (sent by user_auth hooks)
Phoenix.PubSub.broadcast(
Towerops.PubSub,
"organization:#{organization.id}:alerts",
{:alert_changed, organization.id}
)
# Should not crash and should remain connected
# Verify we can still render the page
html = render(view)
assert html =~ organization.name
end
end
defp create_device(organization, site, name \\ "Test Device", ip \\ "192.168.1.1") do