defmodule Microwaveprop.Workers.HrrrFetchWorker do @moduledoc false use Oban.Worker, queue: :hrrr, max_attempts: 20 alias Microwaveprop.Weather alias Microwaveprop.Weather.HrrrClient alias Microwaveprop.Weather.SoundingParams @impl Oban.Worker def backoff(%Oban.Job{attempt: attempt}) do # Exponential backoff: 2m, 4m, 8m, 16m, 32m, 1h, 2h, 4h, 6h, 6h, ... min(120 * Integer.pow(2, attempt - 1), _six_hours = 21_600) end @impl Oban.Worker def perform(%Oban.Job{args: args}) do %{"lat" => raw_lat, "lon" => raw_lon, "valid_time" => valid_time_str} = args {:ok, valid_time, _} = DateTime.from_iso8601(valid_time_str) {lat, lon} = Weather.round_to_hrrr_grid(raw_lat, raw_lon) if Weather.has_hrrr_profile?(lat, lon, valid_time) do :ok else case HrrrClient.fetch_profile(lat, lon, valid_time) do {:ok, data} -> params = SoundingParams.derive(data.profile) attrs = maybe_add_derived_params( %{ valid_time: valid_time, lat: lat, lon: lon, run_time: data.run_time, profile: data.profile, hpbl_m: data.hpbl_m, pwat_mm: data.pwat_mm, surface_temp_c: data.surface_temp_c, surface_dewpoint_c: data.surface_dewpoint_c, surface_pressure_mb: data.surface_pressure_mb }, params ) Weather.upsert_hrrr_profile(attrs) :ok {:error, reason} -> if permanent_failure?(reason) do {:cancel, reason} else {:error, reason} end end end end # 404 means the HRRR data doesn't exist (pre-2014, etc.) — will never succeed defp permanent_failure?("HRRR idx HTTP 404"), do: true defp permanent_failure?("HRRR grib HTTP 404"), do: true defp permanent_failure?(:outside_grid), do: true defp permanent_failure?(_), do: false defp maybe_add_derived_params(attrs, nil), do: attrs defp maybe_add_derived_params(attrs, params) do Map.merge(attrs, %{ surface_refractivity: params.surface_refractivity, min_refractivity_gradient: params.min_refractivity_gradient, ducting_detected: params.ducting_detected, duct_characteristics: params.duct_characteristics }) end end