ruvector/scripts/deploy_brain_services.sh
rUv bd1e253755 feat(brain): ADR-130 service split — SSE proxy, worker, internal queue
* fix(brain): SSE connection limiter, pipeline rate limit, Firestore pagination fallback (ADR-130)

Three fixes for recurring pi.ruv.io outages:

1. SSE connection limiter (max 50) — prevents MCP reconnect storms from
   exhausting Cloud Run concurrency slots. Tracks active count with
   AtomicUsize, rejects excess with 429.

2. Pipeline optimize rate limiter — max 1 concurrent request with 30s
   cooldown. Prevents scheduler thundering herd from CPU-saturating
   the instance.

3. Firestore pagination offset fallback — when page tokens go stale
   after OOM restart (400 Bad Request), switches to offset-based
   pagination to load all documents instead of stopping at first batch.

Also adds /v1/ready lightweight probe (zero-cost, no state access)
for Cloud Run health checks.

ADR-130 documents the full decoupling architecture (SSE service split).

Co-Authored-By: claude-flow <ruv@ruv.net>

* feat(brain): ADR-130 service split — SSE proxy, worker binary, internal queue

Implements full MCP SSE decoupling to eliminate recurring outages:

1. ruvbrain-sse: Thin SSE proxy (308 lines) that manages MCP connections
   independently from the API. Max 200 concurrent SSE, forwards JSON-RPC
   to the API, polls /internal/queue/drain for responses. No business logic.

2. ruvbrain-worker: Batch worker binary (202 lines) for Cloud Run Jobs.
   Runs scheduler actions (train, drift, transfer, graph, cleanup, attractor)
   with direct Firestore access. Runs once and exits.

3. Internal queue endpoints on the API:
   - POST /internal/queue/push (forward JSON-RPC to session)
   - GET /internal/queue/drain (poll for responses)
   - POST /internal/session/create (register session)
   - DELETE /internal/session/:id (cleanup)

4. Deploy infrastructure:
   - Dockerfile.sse, Dockerfile.worker
   - cloudbuild-sse.yaml, cloudbuild-worker.yaml
   - scripts/deploy_brain_services.sh [api|sse|worker|all]

Architecture: SSE (500 concurrency, 512MB) → API (80 concurrency, 4GB) ← Worker (Cloud Run Job, 4GB)

Co-Authored-By: claude-flow <ruv@ruv.net>
2026-03-30 11:54:01 -04:00

70 lines
2.3 KiB
Bash
Executable file

#!/usr/bin/env bash
set -euo pipefail
# Deploy ADR-130 brain service split
# Usage: ./scripts/deploy_brain_services.sh [api|sse|worker|all]
PROJECT=ruv-dev
REGION=us-central1
deploy_api() {
echo "=== Deploying ruvbrain-api ==="
gcloud builds submit --config=crates/mcp-brain-server/cloudbuild.yaml --project=$PROJECT
gcloud run deploy ruvbrain \
--image=gcr.io/$PROJECT/ruvbrain:latest \
--region=$REGION \
--memory=4Gi --cpu=2 \
--concurrency=80 --max-instances=15 --min-instances=1 \
--timeout=300 --session-affinity \
--allow-unauthenticated
}
deploy_sse() {
echo "=== Deploying ruvbrain-sse ==="
# Build SSE image
gcloud builds submit \
--config=crates/mcp-brain-server/cloudbuild-sse.yaml \
--project=$PROJECT
# Deploy SSE service
gcloud run deploy ruvbrain-sse \
--image=gcr.io/$PROJECT/ruvbrain-sse:latest \
--region=$REGION \
--memory=512Mi --cpu=1 \
--concurrency=500 --max-instances=10 --min-instances=0 \
--timeout=3600 --session-affinity \
--allow-unauthenticated \
--set-env-vars="BRAIN_API_URL=https://ruvbrain-HASH.us-central1.run.app,RUST_LOG=info"
# Note: BRAIN_API_URL needs the actual Cloud Run URL of ruvbrain-api
}
deploy_worker() {
echo "=== Deploying ruvbrain-worker ==="
# Build worker image
gcloud builds submit \
--config=crates/mcp-brain-server/cloudbuild-worker.yaml \
--project=$PROJECT
# Create Cloud Run Job (not a service)
gcloud run jobs create ruvbrain-worker \
--image=gcr.io/$PROJECT/ruvbrain-worker:latest \
--region=$REGION \
--memory=4Gi --cpu=2 \
--max-retries=1 --task-timeout=3600s \
--set-env-vars="RUST_LOG=info" \
--set-secrets=BRAIN_API_KEY=brain-api-key:latest,BRAIN_SIGNING_KEY=brain-signing-key:latest \
2>/dev/null || \
gcloud run jobs update ruvbrain-worker \
--image=gcr.io/$PROJECT/ruvbrain-worker:latest \
--region=$REGION \
--memory=4Gi --cpu=2
}
# Parse argument
case "${1:-all}" in
api) deploy_api ;;
sse) deploy_sse ;;
worker) deploy_worker ;;
all) deploy_api && deploy_sse && deploy_worker ;;
*) echo "Usage: $0 [api|sse|worker|all]"; exit 1 ;;
esac
echo "=== Done ==="