From 73c6703102480c435bf7cbded75fb07144a24757 Mon Sep 17 00:00:00 2001 From: Graham McIntire Date: Mon, 1 Jun 2026 16:50:28 -0500 Subject: [PATCH] perf: debounce BadPacketsLive refresh, remove stale test cases Coalesce rapid PubSub notifications into single 2-second delayed DB query. Remove tests for removed :update_time_display handler. Ultraworked with Sisyphus Co-authored-by: Sisyphus --- lib/aprsme_web/live/bad_packets_live/index.ex | 41 +++++++++++++------ test/aprsme_web/live/map_live/index_test.exs | 6 --- .../live/map_live/integration_test.exs | 3 +- 3 files changed, 29 insertions(+), 21 deletions(-) diff --git a/lib/aprsme_web/live/bad_packets_live/index.ex b/lib/aprsme_web/live/bad_packets_live/index.ex index cb5a1da..0d26072 100644 --- a/lib/aprsme_web/live/bad_packets_live/index.ex +++ b/lib/aprsme_web/live/bad_packets_live/index.ex @@ -7,24 +7,24 @@ defmodule AprsmeWeb.BadPacketsLive.Index do alias Aprsme.BadPacket alias Aprsme.Repo + @debounce_ms 2_000 + @impl true def mount(_params, _session, socket) do if connected?(socket) do - # Subscribe to Postgres notifications for bad packets :ok = Phoenix.PubSub.subscribe(Aprsme.PubSub, "postgres:aprsme_events") - # Load initial bad packets bad_packets = fetch_bad_packets() - # Extra safeguard to ensure we never show more than 100 limited_packets = Enum.take(bad_packets, 100) {:ok, assign(socket, bad_packets: limited_packets, loading: false, - last_updated: DateTime.utc_now() + last_updated: DateTime.utc_now(), + refresh_timer: nil )} else - {:ok, assign(socket, bad_packets: [], loading: false, last_updated: nil)} + {:ok, assign(socket, bad_packets: [], loading: false, last_updated: nil, refresh_timer: nil)} end end @@ -39,33 +39,48 @@ defmodule AprsmeWeb.BadPacketsLive.Index do @impl true def handle_event("refresh", _params, socket) do - send(self(), :do_refresh) - {:noreply, assign(socket, loading: true)} + _ = cancel_timer(socket.assigns.refresh_timer) + socket = assign(socket, loading: true) + {:noreply, do_debounced_refresh(socket)} end @impl true def handle_info({:postgres_notify, _payload}, socket) do - # Optionally filter payload for bad packet events - send(self(), :do_refresh) - {:noreply, socket} + {:noreply, debounce_refresh(socket)} end @impl true def handle_info(:do_refresh, socket) do bad_packets = fetch_bad_packets() - # Extra safeguard to ensure we never show more than 100 limited_packets = Enum.take(bad_packets, 100) {:noreply, assign(socket, bad_packets: limited_packets, loading: false, - last_updated: DateTime.utc_now() + last_updated: DateTime.utc_now(), + refresh_timer: nil )} end + defp debounce_refresh(socket) do + _ = cancel_timer(socket.assigns.refresh_timer) + timer_ref = Process.send_after(self(), :do_refresh, @debounce_ms) + assign(socket, refresh_timer: timer_ref) + end + + defp do_debounced_refresh(socket) do + timer_ref = Process.send_after(self(), :do_refresh, @debounce_ms) + assign(socket, refresh_timer: timer_ref) + end + + defp cancel_timer(nil), do: :ok + + defp cancel_timer(ref) do + Process.cancel_timer(ref) + end + defp fetch_bad_packets(limit \\ 100) do - # Hard cap at 100 to prevent showing too many records actual_limit = min(limit, 100) BadPacket diff --git a/test/aprsme_web/live/map_live/index_test.exs b/test/aprsme_web/live/map_live/index_test.exs index bd8fe23..b5adfe8 100644 --- a/test/aprsme_web/live/map_live/index_test.exs +++ b/test/aprsme_web/live/map_live/index_test.exs @@ -291,12 +291,6 @@ defmodule AprsmeWeb.MapLive.IndexTest do assert render(view) =~ "aprs-map" end - test "responds to :update_time_display", %{conn: conn} do - {:ok, view, _html} = live(conn, "/", on_error: :warn) - send(view.pid, :update_time_display) - assert render(view) =~ "aprs-map" - end - test "responds to :cleanup_old_packets", %{conn: conn} do {:ok, view, _html} = live(conn, "/", on_error: :warn) send(view.pid, :cleanup_old_packets) diff --git a/test/aprsme_web/live/map_live/integration_test.exs b/test/aprsme_web/live/map_live/integration_test.exs index 1c07024..b265225 100644 --- a/test/aprsme_web/live/map_live/integration_test.exs +++ b/test/aprsme_web/live/map_live/integration_test.exs @@ -298,12 +298,11 @@ defmodule AprsmeWeb.MapLive.IntegrationTest do end describe "MapLive handle_info coverage" do - test ":cleanup_old_packets, :update_time_display, :reload_historical_packets do not crash", %{conn: conn} do + test ":cleanup_old_packets, :reload_historical_packets do not crash", %{conn: conn} do {:ok, view, _html} = live(conn, "/?lat=33.0&lng=-96.0&z=10", on_error: :warn) render_hook(view, "map_ready", %{}) send(view.pid, :cleanup_old_packets) - send(view.pid, :update_time_display) send(view.pid, :reload_historical_packets) Process.sleep(50) assert render(view) =~ "aprs-map"