Auto-fetch solar index data on contact page when missing

- SolarIndexWorker accepts date arg for specific date fetch
- Contact show page enqueues solar fetch when data missing
- PubSub broadcast on solar data arrival, live-updates page
- Spinner shown while fetching
This commit is contained in:
Graham McIntire 2026-04-02 16:07:38 -05:00
parent 9fe53b4e7b
commit 0e089e8493
No known key found for this signature in database
GPG key ID: F4ABF488E6029E59
2 changed files with 50 additions and 3 deletions

View file

@ -1,11 +1,34 @@
defmodule Microwaveprop.Workers.SolarIndexWorker do
@moduledoc false
use Oban.Worker, queue: :solar, max_attempts: 3
use Oban.Worker, queue: :solar, max_attempts: 3, unique: [period: 3600]
alias Microwaveprop.Weather
alias Microwaveprop.Weather.SolarClient
@impl Oban.Worker
def perform(%Oban.Job{args: %{"date" => date_str}}) do
{:ok, target_date} = Date.from_iso8601(date_str)
case SolarClient.fetch_solar_indices() do
{:ok, all_records} ->
matched = Enum.filter(all_records, fn r -> r.date == target_date end)
Enum.each(matched, &Weather.upsert_solar_index/1)
if matched != [] do
Phoenix.PubSub.broadcast(
Microwaveprop.PubSub,
"contact_enrichment:solar",
{:solar_ready, date_str}
)
end
:ok
{:error, reason} ->
{:error, reason}
end
end
def perform(%Oban.Job{}) do
since_date = Date.add(Date.utc_today(), -7)

View file

@ -12,6 +12,7 @@ defmodule MicrowavepropWeb.ContactLive.Show do
alias Microwaveprop.Weather.HrrrClient
alias Microwaveprop.Workers.ContactWeatherEnqueueWorker
alias Microwaveprop.Workers.HrrrFetchWorker
alias Microwaveprop.Workers.SolarIndexWorker
alias Microwaveprop.Workers.TerrainProfileWorker
require Logger
@ -26,10 +27,11 @@ defmodule MicrowavepropWeb.ContactLive.Show do
Phoenix.PubSub.subscribe(Microwaveprop.PubSub, "contact_enrichment:#{contact.id}")
Phoenix.PubSub.subscribe(Microwaveprop.PubSub, "contact_enrichment:hrrr")
Phoenix.PubSub.subscribe(Microwaveprop.PubSub, "contact_enrichment:weather")
Phoenix.PubSub.subscribe(Microwaveprop.PubSub, "contact_enrichment:solar")
end
weather = load_weather(contact)
solar = load_solar(contact)
solar = maybe_enqueue_solar(contact)
hrrr_path = Weather.hrrr_profiles_for_path(contact)
hrrr = List.first(hrrr_path)
{hrrr, contact, hrrr_jobs_ahead} = maybe_enqueue_hrrr(hrrr, contact)
@ -182,6 +184,11 @@ defmodule MicrowavepropWeb.ContactLive.Show do
)}
end
def handle_info({:solar_ready, _date}, socket) do
solar = load_solar(socket.assigns.contact)
{:noreply, assign(socket, solar: solar)}
end
defp maybe_enqueue_weather(weather, contact) do
has_data = weather.surface_observations != [] or weather.soundings != []
@ -353,6 +360,18 @@ defmodule MicrowavepropWeb.ContactLive.Show do
|> Weather.get_solar_index()
end
defp maybe_enqueue_solar(contact) do
solar = load_solar(contact)
if solar do
solar
else
date = DateTime.to_date(contact.qso_timestamp)
Oban.insert(SolarIndexWorker.new(%{"date" => Date.to_iso8601(date)}))
nil
end
end
@impl true
def render(assigns) do
~H"""
@ -665,7 +684,12 @@ defmodule MicrowavepropWeb.ContactLive.Show do
<div><span class="font-semibold">Kp:</span> {format_kp(@solar.kp_values)}</div>
</div>
<% else %>
<p class="text-sm text-base-content/50 italic">No solar data available for this date.</p>
<div class="text-sm text-base-content/50 italic">
<span class="flex items-center gap-2">
<span class="loading loading-spinner loading-sm"></span>
Fetching solar index data...
</span>
</div>
<% end %>
<div class="divider" />