prop/test/microwaveprop
Graham McIntire 1ec10bec1f
Split ERA5 backfill into submit/poll workers with persistent CDS state
The single Era5MonthBatchWorker pinned an Oban slot for the full 30-45
min a CDS month-tile takes to assemble, and lost the work entirely on a
rolling deploy because the in-flight Task died with the pod. This splits
the flow into two tiny workers and persists the CDS job IDs so deploys
survive.

New pipeline:

1. Era5SubmitWorker (:era5_submit queue) — POSTs both CDS requests in
   parallel, writes an `era5_cds_jobs` row with the returned job IDs,
   and enqueues an Era5PollWorker scheduled +5 min. ~1s of real work.
   Short-circuits when the month-tile is already cached or when a row
   already exists (in-flight from a previous attempt).

2. Era5PollWorker (:era5_poll queue) — reads the row, calls
   Era5Client.check_status/1 for both CDS job IDs, and:
     - returns {:snooze, 300} if either job is still running (Oban
       re-schedules without counting an attempt and releases the slot
       immediately — a pod can keep dozens of tile-months in flight
       without pinning workers)
     - streams both GRIB files to disk via Req into: File.stream!,
       decodes via Wgrib2.extract_grid_messages_from_file, bulk-inserts
       via Era5BatchClient.decode_and_insert/6, deletes the row, and
       DELETEs both completed jobs from CDS to free server-side quota
     - if either leg CDS-reports failed, deletes the row + both CDS
       jobs and returns {:error, reason}

Era5Client gains four testable building blocks:
  submit_job/2               (bare POST → {:ok, job_id})
  check_status/1             (GET → :running | {:done, src} | {:failed, reason})
  download_source_to_file/3  (streams {:url, href} or writes {:body, bin})
  delete_job/1               (DELETE /jobs/:id, treats 200/202/204/404 as :ok)

All Req calls now route through `era5_req_options` so tests can stub
CDS responses via Req.Test.stub(Era5Client, fn).

Era5MonthBatchWorker is retained as a thin forwarder to Era5SubmitWorker
so any jobs already in the :era5_batch queue on prod pods drain cleanly
on the next rolling deploy. Safe to delete in a follow-up.

Adds era5_cds_jobs table with a unique index on
(year, month, tile_lat, tile_lon) so duplicate submits collapse.

New queue config in runtime.exs:
  era5_submit: local_limit 4, rate_limit 30/hour (burst protection)
  era5_poll:   local_limit 20 (polls are cheap GETs)
  era5_batch:  kept at 1 for legacy job drain, delete next cycle
2026-04-13 16:26:26 -05:00
..
backtest Fix wgrib2 -lola binary parsing and add native_surface_refractivity 2026-04-10 08:13:33 -05:00
beacons Fix credo warnings: struct specs, length/1, and test patterns 2026-04-12 10:26:53 -05:00
commercial Add commercial link monitoring via SNMP polling 2026-03-30 13:02:59 -05:00
propagation Wire NEXRAD, native ducts, and commercial links into scoring 2026-04-13 12:08:15 -05:00
qrz Drop gridmap.org dependency, resolve callsigns locally 2026-04-12 17:43:29 -05:00
radio User profiles at /u/:callsign, flexible band input, assorted UX cleanup 2026-04-12 16:13:08 -05:00
terrain Remove unused CaptureLog import in elevation client test 2026-04-12 09:32:47 -05:00
weather Split ERA5 backfill into submit/poll workers with persistent CDS state 2026-04-13 16:26:26 -05:00
workers Split ERA5 backfill into submit/poll workers with persistent CDS state 2026-04-13 16:26:26 -05:00
accounts_test.exs User profiles at /u/:callsign, flexible band input, assorted UX cleanup 2026-04-12 16:13:08 -05:00
backtest_test.exs Phase 9.1: Consolidated backtest report and contest log import 2026-04-10 11:57:15 -05:00
beacon_monitors_test.exs Add beacon monitor registration and fix prod SMTP 2026-04-08 11:30:28 -05:00
beacons_test.exs User profiles at /u/:callsign, flexible band input, assorted UX cleanup 2026-04-12 16:13:08 -05:00
cache_test.exs Cache /contacts, fix map blink, make mode optional 2026-04-12 12:47:25 -05:00
callsign_location_test.exs Drop gridmap.org dependency, resolve callsigns locally 2026-04-12 17:43:29 -05:00
commercial_test.exs Wire NEXRAD, native ducts, and commercial links into scoring 2026-04-13 12:08:15 -05:00
geocoder_test.exs Drop gridmap.org dependency, resolve callsigns locally 2026-04-12 17:43:29 -05:00
markdown_test.exs Add Tier 1 test coverage: EnrichmentStatus, Markdown, health, RemoteIp, Maidenhead 2026-04-06 10:15:38 -05:00
propagation_test.exs Wire NEXRAD, native ducts, and commercial links into scoring 2026-04-13 12:08:15 -05:00
qrz_test.exs Drop gridmap.org dependency, resolve callsigns locally 2026-04-12 17:43:29 -05:00
radio_test.exs Cap "Contacts I'm in" at 100 most recent 2026-04-12 17:04:11 -05:00
terrain_test.exs Rename qsos table to contacts, qso_id to contact_id 2026-04-02 15:52:19 -05:00
weather_grid_test.exs Stop PropagationGridWorker crash-looping on forecast hours 2026-04-13 08:20:28 -05:00
weather_test.exs Reduce dead tuples by using conditional upserts and skip-on-conflict 2026-04-04 17:32:57 -05:00