From 8ffeccbcfc827b2d002f92bf5cf3b53ade2fd554 Mon Sep 17 00:00:00 2001 From: Bharat Kathi Date: Fri, 5 Jun 2026 14:55:54 -0700 Subject: [PATCH] feat(mapache): add live signal-streaming service MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit mapache v3.5.0 extracted the WebSocket / SSE signal-streaming endpoints out of gr26 into a new `live` service (Mapache commits 1eeafd2, 22102fa). Live subscribes to the `query/live/#` republish topic *without* the shared-sub prefix, so every replica sees every signal — which closes the dashboard partial-visibility gap we hit while gr26 was on shared subscriptions with a local-only Hub. This PR brings the service into the cluster: - new live.yaml: Deployment + Service on :7015, replicas=2 with the same minDomains=2 / maxSkew=1 topology spread pattern as the other mapache services. env wires MQTT_USER=mapache + MQTT_PASSWORD from mapache-secrets, CACHE_WINDOW_SEC=60. - kustomization.yaml: live.yaml in resources, live image pinned at 3.5.0 (deploy.yml's awk already includes `live` in its rewrite pattern, so future releases auto-bump alongside the other services). - configmap-kerbecs.yaml: new `live` upstream + three routes — `live-ws` (passthrough), `live-sse` (passthrough), `live` catch-all (default envelope for /live/ping and /live/stats). Routes are ordered before the dashboard catch-all so they match first. --- .../manifests/mapache/configmap-kerbecs.yaml | 34 ++++++++ .../manifests/mapache/kustomization.yaml | 3 + kubernetes/manifests/mapache/live.yaml | 80 +++++++++++++++++++ 3 files changed, 117 insertions(+) create mode 100644 kubernetes/manifests/mapache/live.yaml diff --git a/kubernetes/manifests/mapache/configmap-kerbecs.yaml b/kubernetes/manifests/mapache/configmap-kerbecs.yaml index 5730414..1750443 100644 --- a/kubernetes/manifests/mapache/configmap-kerbecs.yaml +++ b/kubernetes/manifests/mapache/configmap-kerbecs.yaml @@ -66,6 +66,12 @@ data: instances: - http://gr26.mapache.svc.cluster.local:7005 + live: + name: mapache-live + version: 0.1.0 + instances: + - http://live.mapache.svc.cluster.local:7015 + query: name: mapache-query version: 0.1.0 @@ -157,6 +163,34 @@ data: strip_prefix: /api envelope: default + # Specific WS/SSE routes need passthrough so kerbecs doesn't wrap + # the response envelope or interfere with the connection upgrade. + # The catch-all `live` route below uses default envelope for the + # plain HTTP endpoints (/live/ping, /live/stats). + - name: live-ws + match: + path: /api/live/ws + upstream: live + rewrite: + strip_prefix: /api + envelope: passthrough + + - name: live-sse + match: + path: /api/live/sse + upstream: live + rewrite: + strip_prefix: /api + envelope: passthrough + + - name: live + match: + path: /api/live/* + upstream: live + rewrite: + strip_prefix: /api + envelope: default + - name: query match: path: /api/query/* diff --git a/kubernetes/manifests/mapache/kustomization.yaml b/kubernetes/manifests/mapache/kustomization.yaml index baa3e55..3434ae7 100644 --- a/kubernetes/manifests/mapache/kustomization.yaml +++ b/kubernetes/manifests/mapache/kustomization.yaml @@ -26,6 +26,7 @@ resources: - auth.yaml - vehicle.yaml - gr26.yaml + - live.yaml - query.yaml - foreman.yaml - dashboard.yaml @@ -38,6 +39,8 @@ images: newTag: 3.5.0 - name: ghcr.io/gaucho-racing/mapache/gr26 newTag: 3.5.0 + - name: ghcr.io/gaucho-racing/mapache/live + newTag: 3.5.0 - name: ghcr.io/gaucho-racing/mapache/query newTag: 3.5.0 - name: ghcr.io/gaucho-racing/mapache/foreman diff --git a/kubernetes/manifests/mapache/live.yaml b/kubernetes/manifests/mapache/live.yaml new file mode 100644 index 0000000..a81fa7d --- /dev/null +++ b/kubernetes/manifests/mapache/live.yaml @@ -0,0 +1,80 @@ +# live: WebSocket / SSE signal-streaming service. +# +# Subscribes to the `query/live/#` republish topic (non-shared) so every +# replica sees every signal — this is what unblocks the dashboard from +# the gr26 shared-sub partial-visibility issue. The in-process Hub + +# WebSocket endpoint that used to live on gr26 was extracted into this +# service in v3.5.0 (Mapache commit 22102fa). +# +# Cache window (CACHE_WINDOW_SEC=60) is the ring buffer length each +# replica keeps for newly-connecting clients. State is per-pod; a pod +# restart drops its cache, and clients that reconnect onto another pod +# see only that pod's cache for the first 60s. + +apiVersion: apps/v1 +kind: Deployment +metadata: + name: live + namespace: mapache +spec: + replicas: 2 + selector: + matchLabels: + app: live + template: + metadata: + labels: + app: live + spec: + # Spread across at least 2 nodes (minDomains) but tolerate skew + # up to 1 (so 3 replicas → [2,1], not forced [1,1,1]). + topologySpreadConstraints: + - maxSkew: 1 + minDomains: 2 + topologyKey: kubernetes.io/hostname + whenUnsatisfiable: DoNotSchedule + labelSelector: + matchLabels: + app: live + containers: + - name: live + image: ghcr.io/gaucho-racing/mapache/live:latest + ports: + - containerPort: 7015 + resources: + requests: + cpu: 50m + memory: 256Mi + limits: + cpu: 500m + memory: 512Mi + env: + - name: ENV + value: PROD + - name: PORT + value: "7015" + - name: MQTT_HOST + value: gr-mqtt.gauchoracing.com + - name: MQTT_PORT + value: "1883" + - name: MQTT_USER + value: mapache + - name: MQTT_PASSWORD + valueFrom: + secretKeyRef: + name: mapache-secrets + key: MQTT_PASSWORD + - name: CACHE_WINDOW_SEC + value: "60" +--- +apiVersion: v1 +kind: Service +metadata: + name: live + namespace: mapache +spec: + selector: + app: live + ports: + - port: 7015 + targetPort: 7015