prop/lib/microwaveprop/weather
Graham McIntire 9edaee9344
feat(weather): GridCache backend pluggable, Valkey for cross-pod cache
Each cached HRRR valid_time is ~32 MiB compressed × cap of 8 = up to
256 MiB per pod. With 4 hot pods + 1 backfill that's ~1.25 GiB of
cluster RAM holding identical content. Replacing the per-pod ETS
replicas with a single shared Valkey copy collapses that to ~256 MiB
total (off-pod) and makes the BEAM heap on each replica meaningfully
smaller — directly addresses the headroom the 2026-05-03 OOM cascade
ate into.

* New `Microwaveprop.Valkey`: single Redix connection (named conn,
  sync_connect: false, exit_on_disconnection: false). `start_link/0`
  returns `:ignore` when VALKEY_URL is unset so dev/test boot without
  Valkey. Helpers wrap GET/MGET/SET-with-TTL/ZADD/ZREVRANGE/SCAN with
  `:erlang.term_to_binary` round-tripping under the safe atom flag.

* `Microwaveprop.Weather.GridCache` now branches on
  `Valkey.configured?/0`. Public API is identical so callers (Weather,
  GridCachePruneWorker, MapLive) don't change. ETS path is preserved
  unchanged for dev/test.

* Storage layout when on Valkey:
    prop:wg:vts                   ZSET of valid_time iso8601 strings
    prop:wg:<vt>:<lat>:<lon>      one chunk per 5°×5° spatial bucket
  fetch_bounds MGETs only the chunks intersecting the viewport, so a
  regional view is 1-4 round-trips instead of pulling the full grid.

* Per-key TTL = 8 h (matches the ETS valid_time cap). Eviction is
  automatic; prune_keep_latest is a no-op on Valkey, prune_older_than
  uses ZRANGEBYSCORE + DEL.

* All Valkey errors fall back to disk (ScalarFile.read_bounds), logged
  as warnings — page works through Valkey outages, no user-visible
  break beyond a one-shot latency bump.

ScoreCache, Microwaveprop.Cache, NexradCache, telemetry/Postgres
protocol/libcluster registry tables remain ETS — they're sub-ms
hot-path lookups where a network hop would be felt.

VALKEY_URL must be present in prop-secrets for production rollout
(applied out-of-band, secret.yaml is git-ignored).
2026-05-03 17:00:51 -05:00
..
grib2 fix: April 2026 codebase review — address 13 bugs across propagation chain 2026-04-25 10:52:51 -05:00
frontal_analysis.ex fix(prod-build): silence Nx.* undefined warnings in dev/test-only modules 2026-04-30 12:19:16 -05:00
gefs_client.ex fix: log every silent error path so failures surface in k8s logs 2026-04-27 14:31:30 -05:00
gefs_profile.ex feat(gefs): scaffold extended-horizon forecast ingestion 2026-04-18 14:28:44 -05:00
grid_cache.ex feat(weather): GridCache backend pluggable, Valkey for cross-pod cache 2026-05-03 17:00:51 -05:00
hrdps_client.ex feat(hrdps): HrdpsClient — fetch_grid for Canadian propagation grid 2026-04-29 16:58:47 -05:00
hrdps_profile.ex feat(hrdps): hrdps_profiles partitioned table + HrdpsProfile schema 2026-04-29 17:12:41 -05:00
hrrr_client.ex fix: log swallowed async task exits in GEFS scoring and HRRR range fetch 2026-04-27 14:22:10 -05:00
hrrr_climatology.ex fix(logging): suppress /metrics logs and harden scorer hot path 2026-04-21 10:44:25 -05:00
hrrr_native_client.ex Fix credo warnings: struct specs, length/1, and test patterns 2026-04-12 10:26:53 -05:00
hrrr_native_profile.ex Extend skew-T plot to cover the full troposphere 2026-04-14 17:25:58 -05:00
hrrr_point_enqueuer.ex feat: harden /map analysis breakdown + move Plausible to root layout 2026-04-21 15:56:30 -05:00
hrrr_profile.ex Add dialyzer specs and types across the codebase 2026-04-12 08:55:04 -05:00
hrrr_profile_lookup.ex fix(skewt): only fall back to profiles with all 13 pressure levels 2026-04-25 14:19:56 -05:00
iem_client.ex fix(path): handle ProfilesFile cell shape correctly + log async exits 2026-04-25 15:57:20 -05:00
iem_rate_limiter.ex perf(weather): adaptive IemRateLimiter + rebatch mix task 2026-04-24 12:57:25 -05:00
iemre_observation.ex Add dialyzer specs and types across the codebase 2026-04-12 08:55:04 -05:00
map_layers.ex perf(weather): serve /weather from chunked scalar artifacts 2026-04-28 17:15:36 -05:00
metar_5min_observation.ex Add dialyzer specs and types across the codebase 2026-04-12 08:55:04 -05:00
narr_client.ex fix(dialyzer): actually fix LiveTable warnings instead of hiding them 2026-04-21 12:58:10 -05:00
narr_profile.ex Rename ERA5 → NARR across the codebase 2026-04-16 09:22:23 -05:00
ncei_metar_client.ex feat(telemetry): broaden Instrument span coverage 2026-04-18 17:25:33 -05:00
nexrad_cache.ex fix(dialyzer): clear 125+ warnings under strict flags 2026-04-21 10:30:06 -05:00
nexrad_client.ex test: expand coverage and refactor to idiomatic style 2026-04-23 13:28:42 -05:00
nexrad_observation.ex Add dialyzer specs and types across the codebase 2026-04-12 08:55:04 -05:00
rebatch_asos.ex perf(weather): asos_day — one job per unique (station, UTC date) 2026-04-24 13:19:20 -05:00
rtma_client.ex fix(path): handle ProfilesFile cell shape correctly + log async exits 2026-04-25 15:57:20 -05:00
rtma_observation.ex Add dialyzer specs and types across the codebase 2026-04-12 08:55:04 -05:00
scalar_file.ex fix(weather): snap HRDPS reads to nearest valid_time within 6h 2026-04-30 13:46:32 -05:00
skewt_params.ex feat(skewt): add wet-bulb / virtual-T traces and right-edge level rail 2026-04-25 14:24:28 -05:00
solar_client.ex feat(telemetry): broaden Instrument span coverage 2026-04-18 17:25:33 -05:00
solar_index.ex Add dialyzer specs and types across the codebase 2026-04-12 08:55:04 -05:00
sounding.ex Add dialyzer specs and types across the codebase 2026-04-12 08:55:04 -05:00
sounding_params.ex fix: April 2026 codebase review — address 13 bugs across propagation chain 2026-04-25 10:52:51 -05:00
station.ex Add dialyzer specs and types across the codebase 2026-04-12 08:55:04 -05:00
surface_observation.ex Add dialyzer specs and types across the codebase 2026-04-12 08:55:04 -05:00
theta_e.ex Guard against zero specific humidity in theta-e computation 2026-04-11 12:52:32 -05:00
uwyo_sounding_client.ex feat(telemetry): wide instrumentation + bump hrrr to 2 per pod 2026-04-18 16:33:34 -05:00
weather_layers.ex refactor: deduplicate helpers and simplify Scorer 2026-04-28 14:14:34 -05:00