Rust `prop-grid-rs` has been validated end-to-end on talos5 on the streamed-bands image (main-1776635096-6d91461): real chain steps complete in ~7 s each and the peak-heap refactor landed. Changes: - `PropagationGridWorker.seed_chain` now enqueues a single f00 Oban job instead of f00–f18. The f00 analysis-hour keeps its enrichment (native-level duct, NEXRAD composite, commercial-link boost, ProfilesFile write) and the GridCache broadcast. - `GridTaskEnqueuer.seed/1` is called again so grid_tasks gets the 18 forecast-hour rows the Rust worker claims. - Test asserts only one Oban job is enqueued and the matching 18 grid_tasks rows land in the DB. - `deployment-grid-rs.yaml` flips `PROP_SCORES_DIR` from `/data/scores_shadow` to `/data/scores` so Rust writes to the live score tree. No file collision — Elixir only writes the f00 files. The hot pod memory shrink (6 Gi → 1 Gi) is deferred until one full hourly cycle runs clean under the new split.
100 lines
3.4 KiB
YAML
100 lines
3.4 KiB
YAML
apiVersion: apps/v1
|
||
kind: Deployment
|
||
metadata:
|
||
name: prop-grid-rs
|
||
namespace: prop
|
||
# Phase 2 cutover: Rust writes directly to /data/scores. Elixir only
|
||
# runs the f00 analysis-hour step (which carries enrichment Rust
|
||
# doesn't own yet — native-level duct merge, NEXRAD composite,
|
||
# commercial-link degradation, ProfilesFile write). f01..f18 land
|
||
# here from the Rust worker.
|
||
spec:
|
||
replicas: 1
|
||
minReadySeconds: 5
|
||
strategy:
|
||
type: RollingUpdate
|
||
rollingUpdate:
|
||
maxSurge: 0
|
||
maxUnavailable: 1
|
||
selector:
|
||
matchLabels:
|
||
app: prop-grid-rs
|
||
template:
|
||
metadata:
|
||
labels:
|
||
app: prop-grid-rs
|
||
tier: grid-rs
|
||
spec:
|
||
# Pin to talos5 — the 32 GB NUC with NVMe. The worker peaks at ~500 Mi
|
||
# steady-state but benefits from local NVMe for the NFS scores-dir
|
||
# writes (faster fsync) and from never sharing the node with a hot
|
||
# Elixir pod. Label talos5 with `prop-grid-rs=primary` and taint it
|
||
# `workload=grid-rs:NoSchedule` to enforce this.
|
||
nodeSelector:
|
||
prop-grid-rs: "primary"
|
||
tolerations:
|
||
- key: workload
|
||
operator: Equal
|
||
value: grid-rs
|
||
effect: NoSchedule
|
||
imagePullSecrets:
|
||
- name: forgejo-registry
|
||
securityContext:
|
||
runAsUser: 65534
|
||
runAsNonRoot: true
|
||
fsGroup: 65534
|
||
seccompProfile:
|
||
type: RuntimeDefault
|
||
containers:
|
||
- name: prop-grid-rs
|
||
# Image built by a new CI pipeline from rust/prop_grid_rs/.
|
||
# Multi-arch (amd64 + arm64) — reuses the repo's existing
|
||
# buildx wiring.
|
||
image: git.mcintire.me/graham/prop-grid-rs:main-1776635096-6d91461 # {"$imagepolicy": "flux-system:prop-grid-rs"}
|
||
imagePullPolicy: IfNotPresent
|
||
env:
|
||
# Elixir secrets bundle carries DATABASE_URL already. Rust
|
||
# reads it directly (sqlx connects with the same URL).
|
||
- name: HRRR_BASE_URL
|
||
value: "http://skippy.w5isp.com:8080"
|
||
- name: PROP_SCORES_DIR
|
||
value: "/data/scores"
|
||
- name: RUST_LOG
|
||
value: "info"
|
||
- name: PROP_GRID_RS_PG_CONNS
|
||
value: "4"
|
||
envFrom:
|
||
- secretRef:
|
||
name: prop-secrets
|
||
# No HTTP surface. Liveness is "the process is still running";
|
||
# let the kubelet restart us if we crash. Claiming work from
|
||
# grid_tasks is the implicit readiness signal — an idle pod is
|
||
# still healthy (the queue is simply empty).
|
||
resources:
|
||
requests:
|
||
cpu: 100m
|
||
memory: 512Mi
|
||
limits:
|
||
cpu: "4"
|
||
# OOM at 1 Gi during active chain work (92k points × 23
|
||
# bands ≈ 2.1M scores, plus decoded GRIB2 buffers, plus
|
||
# wgrib2 subprocess memory). 2 Gi leaves headroom; we're
|
||
# still an order of magnitude below the 6 Gi Elixir budget.
|
||
memory: 2Gi
|
||
securityContext:
|
||
allowPrivilegeEscalation: false
|
||
runAsNonRoot: true
|
||
runAsUser: 65534
|
||
capabilities:
|
||
drop:
|
||
- ALL
|
||
seccompProfile:
|
||
type: RuntimeDefault
|
||
volumeMounts:
|
||
- name: data
|
||
mountPath: /data
|
||
volumes:
|
||
- name: data
|
||
nfs:
|
||
server: 10.0.15.103
|
||
path: /data
|