From 1406ae97f04ed03cb037c486e98f139a279d38b8 Mon Sep 17 00:00:00 2001 From: Graham McIntire Date: Sat, 5 Jul 2025 14:34:34 -0500 Subject: [PATCH] performance improvements --- assets/js/app.js | 2 +- lib/aprsme/packets.ex | 3 +- lib/aprsme_web/live/map_live/index.ex | 112 +++++++++++++------------- 3 files changed, 60 insertions(+), 57 deletions(-) diff --git a/assets/js/app.js b/assets/js/app.js index a59dcf5..76b7419 100644 --- a/assets/js/app.js +++ b/assets/js/app.js @@ -180,7 +180,7 @@ let liveSocket = new LiveSocket("/live", Socket, { // Show progress bar on live navigation and form submits topbar.config({barColors: {0: "#29d"}, shadowColor: "rgba(0, 0, 0, .3)"}) -window.addEventListener("phx:page-loading-start", _info => topbar.show(300)) +window.addEventListener("phx:page-loading-start", _info => topbar.show(100)) window.addEventListener("phx:page-loading-stop", _info => topbar.hide()) diff --git a/lib/aprsme/packets.ex b/lib/aprsme/packets.ex index 249080e..08650f7 100644 --- a/lib/aprsme/packets.ex +++ b/lib/aprsme/packets.ex @@ -412,9 +412,10 @@ defmodule Aprsme.Packets do def get_recent_packets_optimized(opts \\ %{}) do # Always limit to the last hour for initial load one_hour_ago = DateTime.add(DateTime.utc_now(), -3600, :second) - limit = Map.get(opts, :limit, 500) + limit = Map.get(opts, :limit, 200) # Use a more efficient query that leverages the partial indexes + # Order by received_at DESC to get the most recent packets first base_query = from(p in Packet, where: p.has_position == true, diff --git a/lib/aprsme_web/live/map_live/index.ex b/lib/aprsme_web/live/map_live/index.ex index 2b9d59f..a6c4828 100644 --- a/lib/aprsme_web/live/map_live/index.ex +++ b/lib/aprsme_web/live/map_live/index.ex @@ -38,7 +38,8 @@ defmodule AprsmeWeb.MapLive.Index do if connected?(socket) do Endpoint.subscribe("aprs_messages") Phoenix.PubSub.subscribe(Aprsme.PubSub, "postgres:aprsme_packets") - maybe_start_geolocation(socket) + # Defer IP geolocation to avoid blocking initial page load + Process.send_after(self(), :start_geolocation, 2000) end {:ok, @@ -90,53 +91,6 @@ defmodule AprsmeWeb.MapLive.Index do ) end - @spec maybe_start_geolocation(Socket.t()) :: Socket.t() - defp maybe_start_geolocation(socket) do - if geolocation_enabled?() do - ip_for_geolocation = - if Application.get_env(:aprsme, AprsmeWeb.Endpoint)[:code_reloader] do - # For testing geolocation in dev environment, use a public IP address. - # This will be geolocated to Mountain View, CA. - "8.8.8.8" - else - extract_ip(socket) - end - - if valid_ip_for_geolocation?(ip_for_geolocation) do - start_geolocation_task(ip_for_geolocation) - end - end - - socket - end - - defp geolocation_enabled? do - Application.get_env(:aprsme, :disable_aprs_connection, false) != true - end - - defp extract_ip(socket) do - case socket.private[:connect_info][:peer_data][:address] do - {a, b, c, d} -> "#{a}.#{b}.#{c}.#{d}" - {a, b, c, d, e, f, g, h} -> "#{a}:#{b}:#{c}:#{d}:#{e}:#{f}:#{g}:#{h}" - _ -> nil - end - end - - defp valid_ip_for_geolocation?(ip) do - ip && !String.starts_with?(ip, "127.") && !String.starts_with?(ip, "::1") - end - - defp start_geolocation_task(ip) do - Task.start(fn -> - try do - get_ip_location(ip) - rescue - _error -> - send(self(), {:ip_location, @default_center}) - end - end) - end - @impl true def handle_event("bounds_changed", %{"bounds" => bounds}, socket) do handle_bounds_update(bounds, socket) @@ -211,8 +165,8 @@ defmodule AprsmeWeb.MapLive.Index do def handle_event("map_ready", _params, socket) do socket = assign(socket, map_ready: true) - # Always trigger reload of historical packets with the current value - send(self(), :reload_historical_packets) + # Load historical packets with a small delay to ensure map is fully ready + Process.send_after(self(), :reload_historical_packets, 100) # If we have pending geolocation, zoom to it now socket = @@ -317,6 +271,8 @@ defmodule AprsmeWeb.MapLive.Index do def handle_info({:postgres_packet, packet}, socket), do: handle_info_postgres_packet(packet, socket) + def handle_info(:start_geolocation, socket), do: handle_info_start_geolocation(socket) + def handle_info(%Phoenix.Socket.Broadcast{topic: "aprs_messages", event: "packet", payload: packet}, socket), do: handle_info({:postgres_packet, packet}, socket) @@ -454,6 +410,52 @@ defmodule AprsmeWeb.MapLive.Index do {:noreply, assign(socket, visible_packets: new_visible_packets)} end + defp handle_info_start_geolocation(socket) do + if geolocation_enabled?() do + ip_for_geolocation = + if Application.get_env(:aprsme, AprsmeWeb.Endpoint)[:code_reloader] do + # For testing geolocation in dev environment, use a public IP address. + # This will be geolocated to Mountain View, CA. + "8.8.8.8" + else + extract_ip(socket) + end + + if valid_ip_for_geolocation?(ip_for_geolocation) do + start_geolocation_task(ip_for_geolocation) + end + end + + {:noreply, socket} + end + + defp geolocation_enabled? do + Application.get_env(:aprsme, :disable_aprs_connection, false) != true + end + + defp extract_ip(socket) do + case socket.private[:connect_info][:peer_data][:address] do + {a, b, c, d} -> "#{a}.#{b}.#{c}.#{d}" + {a, b, c, d, e, f, g, h} -> "#{a}:#{b}:#{c}:#{d}:#{e}:#{f}:#{g}:#{h}" + _ -> nil + end + end + + defp valid_ip_for_geolocation?(ip) do + ip && !String.starts_with?(ip, "127.") && !String.starts_with?(ip, "::1") + end + + defp start_geolocation_task(ip) do + Task.start(fn -> + try do + get_ip_location(ip) + rescue + _error -> + send(self(), {:ip_location, @default_center}) + end + end) + end + # Handle replaying the next historical packet @impl true @@ -921,8 +923,8 @@ defmodule AprsmeWeb.MapLive.Index do # Clear existing historical packets socket = push_event(socket, "clear_historical_packets", %{}) - # Load historical packets for the current map bounds and time range - socket = load_historical_packets_for_bounds(socket, socket.assigns.map_bounds) + # Use optimized loading for better performance + socket = load_historical_packets_for_bounds_optimized(socket, socket.assigns.map_bounds) {:noreply, socket} else @@ -1112,14 +1114,14 @@ defmodule AprsmeWeb.MapLive.Index do map_bounds.north ] - # Use the optimized query for initial load + # Use the optimized query for initial load with smaller limit for faster loading packets_module = Application.get_env(:aprsme, :packets_module, Aprsme.Packets) historical_packets = packets_module.get_recent_packets_optimized(%{ bounds: bounds, - # Smaller limit for faster initial load - limit: 500 + # Reduced limit for faster initial load + limit: 200 }) if Enum.empty?(historical_packets) do