defmodule Microwaveprop.Workers.BackfillEnqueueWorker do @moduledoc """ Runs backfill enrichment enqueue as an Oban job so the backfill dashboard returns immediately instead of blocking on the enqueue loop. """ use Oban.Worker, queue: :backfill_enqueue, max_attempts: 1 import Ecto.Query alias Microwaveprop.Radio.Contact alias Microwaveprop.Repo alias Microwaveprop.Workers.ContactWeatherEnqueueWorker require Logger @enrichable [:pending, :queued, :failed] @valid_types ~w(hrrr weather terrain iemre) @impl Oban.Worker def perform(%Oban.Job{args: %{"limit" => limit} = args}) do types = parse_types(args) contacts = Contact |> where([c], not is_nil(c.pos1) or not is_nil(c.grid1)) |> where(^type_filter(types)) |> order_by([c], desc: c.qso_timestamp) |> limit(^limit) |> Repo.all() count = length(contacts) Logger.info("BackfillEnqueue: processing #{count} contacts (types: #{inspect(types)})") Enum.each(contacts, &ContactWeatherEnqueueWorker.enqueue_for_contact(&1, types)) Phoenix.PubSub.broadcast( Microwaveprop.PubSub, "backfill:enqueue_complete", {:enqueue_complete, count} ) :ok end defp parse_types(%{"types" => types}) when is_list(types) do types |> Enum.filter(&(&1 in @valid_types)) |> Enum.map(&String.to_existing_atom/1) end defp parse_types(_), do: [:hrrr, :weather, :terrain, :iemre] defp type_filter(types) do Enum.reduce(types, dynamic(false), fn type, acc -> field = :"#{type}_status" dynamic([c], ^acc or field(c, ^field) in ^@enrichable) end) end end