Commit graph

5 commits

Author SHA1 Message Date
ed2563f4f8
style(rust): apply cargo fmt across prop_grid_rs 2026-04-20 13:20:22 -05:00
65a1b1edb3
feat(rust): OTLP trace export to cluster OTel Collector
New telemetry module wires tracing-subscriber to both a local JSON
fmt layer (keeps kubectl-logs output identical) and an
OpenTelemetry OTLP/gRPC exporter, activated only when
OTEL_EXPORTER_OTLP_ENDPOINT is set. The returned TelemetryGuard
holds the SdkTracerProvider until process shutdown so queued spans
flush before exit.

Both bin targets (worker, hrrr_point_worker) now call
telemetry::init(service_name) at startup; service_name becomes the
OTel service.name attribute so Tempo groups spans per binary.

Tracing instrumentation on the three main work units:
- pipeline::run_chain_step (forecast f01..f18)
- pipeline::run_analysis_step (analysis f00)
- hrrr_points::process_batch (per-QSO point drain)

k8s manifests set OTEL_EXPORTER_OTLP_ENDPOINT to the cluster
collector at otel-collector.observability.svc.cluster.local:4317.
Backend wiring lives in the vntx-infra repo.
2026-04-20 11:59:49 -05:00
a1d2e9f94a
fix(hrrr-points): bind jsonb[] correctly, warn on empty fetch, 2 Gi limit
Three fixes after hrrr-point-rs restarts on the first live drain:

1. Type mismatch (hard error): the `profile` column on `hrrr_profiles`
   is `jsonb[]` (one element per pressure level), but the Rust worker
   was binding a single jsonb array-of-objects cast as `::jsonb`. Every
   insert failed with `column "profile" is of type jsonb[] but
   expression is of type jsonb`. Switched to
   `Vec<sqlx::types::Json<Value>>`, dropped the explicit `::jsonb`
   cast, and enabled sqlx's `json` feature so the encoder maps the
   array into `_jsonb` correctly.

2. Silent zero-inserts: four consecutive 2019-09-22 batches completed
   with `profiles_inserted: 0` and no diagnostic. Most likely the
   upstream archive doesn't keep cycles that old, but without a log
   it looks identical to a snap-mismatch bug. Added a WARN when both
   surface and pressure grids come back empty so fetch-miss vs.
   projection-miss is distinguishable.

3. OOMKilled: the pod took four OOM restarts in ten minutes at 1 Gi.
   A single CONUS decode holds the ~40 MB blob, the ~200 MB wgrib2
   working set, AND the full 92k-cell merged map until all requested
   points drain. 1 Gi has no headroom. Bumped to 2 Gi, matching the
   rest of the per-container budgets in this namespace.
2026-04-20 09:18:52 -05:00
ea73f3164d
fix(grid-rs): drop target/ cache mount, simplify Dockerfile
The docker buildx build step has failed twice since Stream C added the
hrrr_point_worker binary. Dropping the target/ BuildKit cache mount
eliminates the most likely cause (disk pressure inside a persistent
cache shared between the two bin builds). Full rebuild from scratch
adds ~3 min to the build but the failure mode is worth more than the
cache.

Also dropped the empty unit test scaffolding in hrrr_points.rs; the
module is thin glue over fetcher+decoder which already carry coverage.
Integration tests for process_batch/upsert_profile are gated on a live
DB + HRRR mirror and live in tests/ (when added).
2026-04-20 08:30:49 -05:00
4fefb81c24
feat(hrrr-point-rs): Rust binary for per-QSO HRRR enrichment
Phase 3 Stream C Rust side. Completes the HrrrFetchWorker port.

Pipeline:
- db::claim_next_hrrr_task — FOR UPDATE SKIP LOCKED on hrrr_fetch_tasks,
  newest valid_time first. Accepts the points JSONB directly.
- hrrr_points::process_batch — fetch surface + pressure GRIB2 once
  per task (tokio::try_join), decode via the existing wgrib2 plumbing,
  then for each requested point pull the cell and UPSERT INTO
  hrrr_profiles (conflict on lat/lon/valid_time).
- db::complete_hrrr_task / fail_hrrr_task — status transitions; Elixir
  backfill re-enqueues failed rows on next /30-min scan.

Shipping pieces:
- new bin src/bin/hrrr_point_worker.rs
- new module src/hrrr_points.rs (process_batch, upsert_profile)
- new Cargo [[bin]] entry; Dockerfile builds both binaries in one stage
  and ships them in the runtime image so a single CI pipeline covers
  the whole cluster
- k8s/deployment-hrrr-point-rs.yaml (1 replica, 1 Gi limit, anti-affinity
  against prop-grid-rs so chain + point work don't fight for wgrib2
  slots). Uses the same image; command: override picks the right binary.
- kustomization.yaml: include the new deployment so flux applies it
- deployment-grid-rs.yaml: bump readiness initialDelaySeconds 3→15 +
  failureThreshold 3→6 so a slow DB connect during startup can't race
  the first probe

119 Rust tests green.
2026-04-19 18:28:00 -05:00