prop/lib/microwaveprop
Graham McIntire 63f25a9612
Some checks failed
Build prop-grid-rs / Test, build, push (push) Successful in 5m54s
Build and Push / Build and Push Docker Image (push) Failing after 4m44s
perf(grid-rs): dense grid, fused scoring pass, and columnar .pgrid profiles
Reworks the post-fetch half of the propagation pipeline. Fetch and GRIB2
decode were already cheap — measured against a live HRRR cycle, all 39
pressure messages decode via `wgrib2 -lola` in 0.29 s and the 31 MB
byte-range fetch takes ~3 s — so nothing here touches the decoder. All the
cost was downstream.

Also fixes a broken NOTIFY that made every chain step run up to 5 times.

pg_notify
  `NOTIFY propagation_ready, $1` is a Postgres syntax error: NOTIFY is a
  utility statement whose payload must be a literal, so a bind raises
  42601. It shared a transaction with the `status='done'` UPDATE, so every
  successful step rolled back, stayed 'running', and was requeued by
  reclaim_stale_running up to @max_reclaim_attempts times. Elixir's
  NotifyListener never fired either, so ScoreCache warm and the
  "propagation:updated" fan-out were dead.

FieldGrid
  A decoded grid was HashMap<(i32,i32), HashMap<Arc<str>, f32>> — a dense
  rectangular grid stored as ~95k nested hash maps, costing ~4.6M inserts
  on decode, ~3.7M on merge and ~14M lookups across three derivation
  passes. wgrib2 -lola already emits one dense row-major f32 block per
  message, so keep it: dense per-message planes, names hashed once per
  grid into plane ids, NaN as the missing sentinel. This is what forced
  PROP_GRID_RS_PARALLELISM=1 under a 3Gi limit.

Fused pass
  Three 95k-cell derivation passes plus 23 band-major scoring passes over
  a staged Vec<(f64,f64,Conditions,BandInvariants)> (~19MB re-streamed 23
  times) collapse into one pass: levels extracted once per cell, all 23
  bands scored while the cell is hot, scores accumulated cell-major so
  rayon chunks own disjoint slices. Scores land straight in the dense
  score-file body — no ScorePoint scatter.

.pgrid
  The profile artifact was an rmpv tree plus gzip -9, written 30x an hour,
  and ProfilesFile.read_point/3 gunzipped and unpacked the entire 95k-cell
  file to return one cell on every map click and Skew-T load. Replaced
  with a dense cell-major f32 record array carrying a self-describing
  field table. Elixir reads it via :file.pread; .mp.gz and .etf.gz remain
  readable so files written before this drain out of the 48h window.

  Measured on a full CONUS grid (95,073 cells x 48 planes x 23 bands):
    derive + score + build artifacts   0.022 s
    profile write   3.957 s -> 0.006 s (22.0 MB -> 22.4 MB on disk)
    single-cell read   whole-file decode -> 0.5 us
    23 score files     0.003 s

Also
  - hrrr_points: batched UNNEST upsert replacing one awaited INSERT per
    point. Keeps ON CONFLICT DO UPDATE — the PSKR sampler's two-pass loop
    depends on it.
  - fetcher: real semaphore capping in-flight ranges at
    MAX_PARALLEL_RANGES, which the comment claimed but the code did not do
    (it spawned all 27 while the connection pool was sized for 8).
  - metrics: per-stage histogram. Only chain-step and decode durations
    were instrumented, which is why the write cost stayed invisible.
  - profiles_file: parse_valid_time anchors on the known extension set, so
    sibling-suffixed names like <iso>.hrdps.prop no longer parse as
    <iso>.hrdps and vanish from prune and list operations.
  - PROP_GRID_RS_PARALLELISM 1 -> 3. Memory limit held at 3Gi until RSS is
    observed at the new parallelism.
  - cargo fmt over the crate; worker.rs, hrdps_fetcher.rs and nexrad.rs
    were already unformatted at HEAD and the pre-commit hook gates on it.

HRDPS still runs at 0.5 degrees. wgrib2 -lola scales linearly in output
points on rotated lat/lon (12.5 s wall, 202 s CPU for one message at
0.125 degrees) because it has no inverse projection for those grids; a raw
native dump is 0.32 s. The fix is decode-once plus a closed-form
rotated-pole index, left for a follow-up.
2026-08-01 08:23:36 -05:00
..
accounts fix: resolve 18 bugs across LiveViews, schemas, tests, and logic 2026-07-29 07:46:54 -05:00
aprs polish(aprs): consolidate callsign regex, document raise, note negative-sample v1 limit 2026-05-01 13:10:57 -05:00
backtest fix: resolve all dialyzer type errors across project (46→0 project errors) 2026-06-08 17:51:13 -05:00
beacon_measurements feat(api): ingest endpoint for propmonitor beacon measurements 2026-05-13 16:07:04 -05:00
beacon_monitors beacon monitor work 2026-07-22 10:30:21 -05:00
beacons fix: resolve 18 bugs across LiveViews, schemas, tests, and logic 2026-07-29 07:46:54 -05:00
buildings fix: sweep bugs across Python MQTT listener, Elixir PSKR/propagation, and Rust 2026-07-20 19:48:45 -05:00
callsign_location Drop gridmap.org dependency, resolve callsigns locally 2026-04-12 17:43:29 -05:00
canopy fix: resolve 391 Credo issues across codebase 2026-06-12 13:51:32 -05:00
commercial fix: resolve 27 security, architecture, test, and performance audit findings 2026-07-27 18:19:37 -05:00
ionosphere fix: handle GIRO API 404 cleanly — don't dump raw HTML into logs 2026-07-16 07:17:52 -05:00
prom_ex perf(prop): cap ScoreCache LRU + drop eager warmers to fix hot-pod OOMs 2026-04-24 18:49:36 -05:00
propagation perf(grid-rs): dense grid, fused scoring pass, and columnar .pgrid profiles 2026-08-01 08:23:36 -05:00
pskr fix: resolve 18 bugs across LiveViews, schemas, tests, and logic 2026-07-29 07:46:54 -05:00
qrz feat(telemetry): broaden Instrument span coverage 2026-04-18 17:25:33 -05:00
radio fix: resolve 18 bugs across LiveViews, schemas, tests, and logic 2026-07-29 07:46:54 -05:00
rover fix: resolve all 281 credo issues across source and test files 2026-07-29 09:04:21 -05:00
rover_planning fix: resolve 18 bugs across LiveViews, schemas, tests, and logic 2026-07-29 07:46:54 -05:00
space_weather fix: resolve all compiler warnings except framework-generated phoenix_component_verify 2026-05-29 10:18:52 -05:00
terrain fix: resolve all 281 credo issues across source and test files 2026-07-29 09:04:21 -05:00
valkey test: use Mox for Valkey tests without real Redis (55%→88%) 2026-05-07 13:48:08 -05:00
weather fix: resolve all 281 credo issues across source and test files 2026-07-29 09:04:21 -05:00
workers fix: resolve all 281 credo issues across source and test files 2026-07-29 09:04:21 -05:00
accounts.ex feat(admin): beacon monitor reassign, token regen, assigned_by display, user monitor management 2026-07-22 16:27:21 -05:00
application.ex fix: resolve 391 Credo issues across codebase 2026-06-12 13:51:32 -05:00
aprs.ex polish(aprs): consolidate callsign regex, document raise, note negative-sample v1 limit 2026-05-01 13:10:57 -05:00
aprs_repo.ex feat(aprs): add read-only AprsRepo for aprs.me database access 2026-05-01 12:25:33 -05:00
backtest.ex chore(specs): add @spec to public API in accounts/release/backtest 2026-04-21 13:32:42 -05:00
beacon_measurements.ex fix: resolve all 281 credo issues across source and test files 2026-07-29 09:04:21 -05:00
beacon_monitors.ex fix: resolve all 281 credo issues across source and test files 2026-07-29 09:04:21 -05:00
beacons.ex fix: wire pending_edits_query as data_provider for contact edit review table 2026-07-22 08:54:46 -05:00
cache.ex fix: resolve all dialyzer type errors across project (46→0 project errors) 2026-06-08 17:51:13 -05:00
callsign_location.ex Drop gridmap.org dependency, resolve callsigns locally 2026-04-12 17:43:29 -05:00
canopy.ex fix: ensure all unused historical NFS data gets cleaned up 2026-07-20 09:27:36 -05:00
commercial.ex refactor: deduplicate hrrr download, simplify radio/mqtt, fix credo/perf issues 2026-05-07 11:50:29 -05:00
format.ex fix: resolve 27 security, architecture, test, and performance audit findings 2026-07-27 18:19:37 -05:00
geo.ex refactor: deduplicate helpers and simplify Scorer 2026-04-28 14:14:34 -05:00
geocoder.ex feat(telemetry): broaden Instrument span coverage 2026-04-18 17:25:33 -05:00
instrument.ex feat(telemetry): wide instrumentation + bump hrrr to 2 per pod 2026-04-18 16:33:34 -05:00
ionosphere.ex refactor: deduplicate helpers and simplify Scorer 2026-04-28 14:14:34 -05:00
mailer.ex Send mail as prop@w5isp.com with reply-to graham@mcintire.me 2026-04-12 14:00:38 -05:00
markdown.ex fix: resolve all dialyzer type errors across project (46→0 project errors) 2026-06-08 17:51:13 -05:00
moon.ex feat(eme): add /eme Earth-Moon-Earth calculator 2026-04-23 16:18:20 -05:00
oban_error_reporter.ex fix: resolve all dialyzer type errors across project (46→0 project errors) 2026-06-08 17:51:13 -05:00
partition_manager.ex fix: resolve all dialyzer type errors across project (46→0 project errors) 2026-06-08 17:51:13 -05:00
prom_ex.ex fix: stabilize flaky tests + silence PromEx Oban poller in test 2026-04-21 13:49:07 -05:00
propagation.ex fix: resolve all 281 credo issues across source and test files 2026-07-29 09:04:21 -05:00
pskr.ex fix: sweep bugs across Python MQTT listener, Elixir PSKR/propagation, and Rust 2026-07-20 19:48:45 -05:00
qrz.ex Drop gridmap.org dependency, resolve callsigns locally 2026-04-12 17:43:29 -05:00
radio.ex fix: resolve 27 security, architecture, test, and performance audit findings 2026-07-27 18:19:37 -05:00
release.ex feat: clickable band filters on PSK Reporter tab, fix all test & credo issues 2026-07-20 13:01:00 -05:00
repo.ex fix: override Repo.all/2 to accept :limit/:offset opts for Oban Pro compat 2026-07-15 14:41:02 -05:00
repo_listener.ex fix: make RepoListener resilient, bypass pgbouncer for NOTIFY/LISTEN 2026-07-20 13:15:45 -05:00
rover.ex fix: resolve all dialyzer type errors across project (46→0 project errors) 2026-06-08 17:51:13 -05:00
rover_planning.ex refactor: DRY extract_bearer, reuse validation helpers, add query limits 2026-07-21 10:06:12 -05:00
space_weather.ex refactor(db): use explicit on_conflict set clauses over :replace_all_except 2026-04-21 14:22:15 -05:00
terrain.ex Add dialyzer specs and types across the codebase 2026-04-12 08:55:04 -05:00
valkey.ex test: use Mox for Valkey tests without real Redis (55%→88%) 2026-05-07 13:48:08 -05:00
weather.ex fix: resolve 27 security, architecture, test, and performance audit findings 2026-07-27 18:19:37 -05:00