Commit graph

7 commits

Author SHA1 Message Date
FluxCD
76a407c8b1 chore: update prop image to git.mcintire.me/graham/prop-grid-rs:main-1776635096-6d91461 [skip ci] 2026-04-19 21:46:29 +00:00
ca33b8331b
fix(grid-rs): bump memory limit to 2 Gi
1 Gi OOM'd during a real chain step. Each forecast hour loads both a
surface and pressure-level HRRR GRIB2 (~40 MB combined), decodes via
wgrib2 subprocess (which allocates its own buffers), scores 92k grid
points × 23 bands (~2.1M intermediates), and writes 23 score files.
2 Gi absorbs the spike; still ~3× smaller than the Elixir-per-pod
budget we're replacing.
2026-04-19 16:37:05 -05:00
25c3d4f688
fix(grid-rs): bump memory limit to 1 Gi
The real worker binary OOM-killed at 512 Mi on startup. The plan's
512 Mi assumption was speculative — actual Rust RSS at boot includes
sqlx pool buffers, reqwest connection pool, tokio runtime, and
tracing JSON subscriber. 1 Gi leaves room for all of that plus the
steady-state ~500 Mi during a chain step.
2026-04-19 16:35:18 -05:00
FluxCD
90281b8562 chore: update prop image to git.mcintire.me/graham/prop-grid-rs:main-1776634333-2d67cf7 [skip ci] 2026-04-19 21:32:58 +00:00
FluxCD
a40e2d1630 chore: update prop image to git.mcintire.me/graham/prop-grid-rs:main-1776633497-5692d50 [skip ci] 2026-04-19 21:25:02 +00:00
735553e443
feat(flux): add image-automation for prop-grid-rs
Mirrors the Elixir wiring:
- ImageRepository + ImagePolicy scan git.mcintire.me/graham/prop-grid-rs
  for main-<ts>-<sha> tags and pick the highest timestamp.
- ImageUpdateAutomation already covers ./k8s via the Setters strategy,
  so the new setter marker on deployment-grid-rs.yaml means flux will
  rewrite it on every CI push and commit the update back to main.
2026-04-19 16:24:33 -05:00
b80878056d
feat(grid-rs): Rust worker for HRRR f01..f18 propagation chain
Extracts the memory-hostile HRRR fetch → decode → score pipeline for
forecast hours 1–18 into a separate Rust service (`prop-grid-rs`).
Elixir retains f00 with its native-duct + NEXRAD + commercial-link
enrichment; Rust handles the other 18 steps per hourly chain.

Hand-off via a new `grid_tasks` table (`FOR UPDATE SKIP LOCKED` claim
from Rust, Postgrex `NOTIFY propagation_ready` back to Elixir). Rust
writes the same on-disk score-grid format Elixir already uses, to the
same `/data/scores` NFS tree. Phase 1 ships in shadow mode with
PROP_SCORES_DIR=/data/scores_shadow.

Rust crate layout at `rust/prop_grid_rs/` (1:1 module parity with the
Elixir source it ports):
  - grid, region, band_config, scores_file, sounding_params
  - scorer: all 10 factors + composite. Matches the Elixir scorer
    byte-for-byte across 115 golden-fixture samples (5 scenarios
    × 23 bands).
  - decoder: wgrib2 subprocess + Fortran-record lola-binary parser
  - fetcher: HRRR URL derivation + idx cache (1h TTL) + 8-way
    parallel byte-range downloads with 429/5xx retry
  - pipeline: end-to-end chain step, f00 rejected at the boundary
  - db: sqlx grid_tasks claim/complete + propagation_ready NOTIFY
  - bin/worker: tokio main loop, JSON logs, SIGTERM-safe

91 Rust tests + clippy -D warnings clean. 2,158 Elixir tests green.

Elixir additions:
  - `GridTaskEnqueuer` seeds fh=1..18 rows from
    `PropagationGridWorker.seed_chain/0`
  - `NotifyListener` LISTEN → warm `ScoreCache` → PubSub fan-out
  - `ShadowComparator` diffs prod vs shadow `.ntms` bodies
  - `mix rust.golden` task writes the Rust-side golden fixture

k8s: new `deployment-grid-rs.yaml` pinned to talos5 (32 GB NUC) via
`prop-grid-rs=primary` nodeSelector + `workload=grid-rs:NoSchedule`
toleration, 512 Mi limit, sharing the existing NFS `/data` mount.

The plan document is at `plans/vivid-hatching-quail.md` (local to my
workstation); phases 2 (cutover) and 3 (talos5 concurrency tuning)
follow after 72h of shadow-mode parity.
2026-04-19 15:42:49 -05:00