Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 30 additions & 19 deletions .github/workflows/gcp_backend.yml
Original file line number Diff line number Diff line change
Expand Up @@ -70,21 +70,31 @@ jobs:
cache-from: type=registry,ref=gcr.io/${{ vars.GCP_PROJECT_ID }}/${{ env.SERVICE }}:buildcache
cache-to: type=registry,ref=gcr.io/${{ vars.GCP_PROJECT_ID }}/${{ env.SERVICE }}:buildcache,mode=max

- name: Set environment prefix
id: env-prefix
run: |
if [[ "${{ github.event.inputs.environment }}" == "prod" ]]; then
echo "prefix=prod" >> $GITHUB_OUTPUT
else
echo "prefix=dev" >> $GITHUB_OUTPUT
fi

- name: Deploy ${{ env.SERVICE }} to Cloud Run
id: deploy-backend
uses: google-github-actions/deploy-cloudrun@v2
with:
service: ${{ env.SERVICE }}
region: ${{ env.REGION }}
image: gcr.io/${{ vars.GCP_PROJECT_ID }}/${{ env.SERVICE }}
run: |
# Update image in declarative config
IMAGE="gcr.io/${{ vars.GCP_PROJECT_ID }}/${{ env.SERVICE }}:latest"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 :latest tag makes deployments non-deterministic

Both the Docker build step (line 69) and all three deploy steps push/deploy the :latest tag. This means:

  1. There is no stable artifact tied to a specific commit — any concurrent build can overwrite :latest mid-deploy.
  2. Rollback from Git alone is not possible; you would need to rebuild the image.

Consider tagging the image with the Git SHA and using that tag in the deploy:

tags: |
  gcr.io/${{ vars.GCP_PROJECT_ID }}/${{ env.SERVICE }}:latest
  gcr.io/${{ vars.GCP_PROJECT_ID }}/${{ env.SERVICE }}:${{ github.sha }}

Then use ${{ github.sha }} for the IMAGE variable in the deploy steps.

CONFIG="backend/cloudrun/${{ env.SERVICE }}/${{ steps.env-prefix.outputs.prefix }}_${{ env.SERVICE }}.yaml"
sed -i "s|image:.*|image: ${IMAGE}|" "$CONFIG"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Silent sed failure with no verification

The sed -i "s|image:.*|image: ${IMAGE}|" command exits 0 even if no substitution was made (e.g., if the image: line is indented differently, commented out, or the file path is wrong). In that case, gcloud run services replace would be called with the stale image reference already present in the YAML file (gcr.io/based-hardware-dev/backend or gcr.io/based-hardware/backend without a tag), potentially deploying a different image than intended with no workflow failure.

Add a verification step after the sed:

sed -i "s|image:.*|image: ${IMAGE}|" "$CONFIG"
grep -q "${IMAGE}" "$CONFIG" || { echo "ERROR: image line not updated in $CONFIG"; exit 1; }
gcloud run services replace "$CONFIG" \
  --region=${{ env.REGION }} --project=${{ vars.GCP_PROJECT_ID }}

This same issue affects the backend-sync deploy at line 95 and backend-integration deploy at line 114.

gcloud run services replace "$CONFIG" \
--region=${{ env.REGION }} --project=${{ vars.GCP_PROJECT_ID }}

- name: Deploy ${{ env.SERVICE }}-sync to Cloud Run
id: deploy-backend-sync
uses: google-github-actions/deploy-cloudrun@v2
with:
service: ${{ env.SERVICE }}-sync
region: ${{ env.REGION }}
image: gcr.io/${{ vars.GCP_PROJECT_ID }}/${{ env.SERVICE }}
run: |
IMAGE="gcr.io/${{ vars.GCP_PROJECT_ID }}/${{ env.SERVICE }}:latest"
CONFIG="backend/cloudrun/${{ env.SERVICE }}-sync/${{ steps.env-prefix.outputs.prefix }}_${{ env.SERVICE }}-sync.yaml"
sed -i "s|image:.*|image: ${IMAGE}|" "$CONFIG"
gcloud run services replace "$CONFIG" \
--region=${{ env.REGION }} --project=${{ vars.GCP_PROJECT_ID }}

- name: Connect to GKE cluster
run: |
Expand All @@ -98,13 +108,14 @@ jobs:
kubectl -n ${{ vars.ENV }}-omi-backend rollout restart deploy ${{ vars.ENV }}-omi-backend-listen

- name: Deploy ${{ env.SERVICE }}-integration to Cloud Run
id: deploy-backend-integration
uses: google-github-actions/deploy-cloudrun@v2
with:
service: ${{ env.SERVICE }}-integration
region: ${{ env.REGION }}
image: gcr.io/${{ vars.GCP_PROJECT_ID }}/${{ env.SERVICE }}
run: |
IMAGE="gcr.io/${{ vars.GCP_PROJECT_ID }}/${{ env.SERVICE }}:latest"
CONFIG="backend/cloudrun/${{ env.SERVICE }}-integration/${{ steps.env-prefix.outputs.prefix }}_${{ env.SERVICE }}-integration.yaml"
sed -i "s|image:.*|image: ${IMAGE}|" "$CONFIG"
gcloud run services replace "$CONFIG" \
--region=${{ env.REGION }} --project=${{ vars.GCP_PROJECT_ID }}

# If required, use the Cloud Run url output in later steps
- name: Show Output
run: echo ${{ steps.deploy.outputs.url }}
run: |
echo "Deployed all Cloud Run services from declarative configs in backend/cloudrun/"
226 changes: 226 additions & 0 deletions backend/cloudrun/backend-integration/dev_backend-integration.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,226 @@
apiVersion: serving.knative.dev/v1
kind: Service
metadata:
annotations:
run.googleapis.com/ingress: all
labels: {}
name: backend-integration
spec:
template:
metadata:
annotations:
autoscaling.knative.dev/maxScale: '3'
run.googleapis.com/network-interfaces: '[{"network":"omi-dev-vpc-1","subnetwork":"omi-us-central1-dev-vpc-1-subnet-1"}]'
run.googleapis.com/startup-cpu-boost: 'true'
run.googleapis.com/vpc-access-egress: private-ranges-only
labels:
run.googleapis.com/startupProbeType: Default
spec:
containerConcurrency: 80
containers:
- env:
- name: BUCKET_APP_THUMBNAILS
value: plugin_resources
- name: BUCKET_CHAT_FILES
value: dev_chat_files
- name: BUCKET_PLUGINS_LOGOS
value: plugin_resources
- name: BUCKET_SPEECH_PROFILES
value: speech-profiles-dev
- name: BUCKET_TEMPORAL_SYNC_LOCAL
value: syncing-local-development
- name: DD_LOGS_ENABLED
value: 'false'
- name: DEEPGRAM_SELF_HOSTED_ENABLED
value: 'true'
- name: DEEPGRAM_SELF_HOSTED_URL
value: https://dg.omiapi.com
- name: FAIR_USE_3DAY_SPEECH_MS
value: '28800000'
- name: FAIR_USE_BUCKET_SECONDS
value: '60'
- name: FAIR_USE_CHECK_INTERVAL_SECONDS
value: '300'
- name: FAIR_USE_CLASSIFIER_ABUSE_SCORE_THRESHOLD
value: '0.7'
- name: FAIR_USE_CLASSIFIER_COOLDOWN_SECONDS
value: '43200'
- name: FAIR_USE_CLASSIFIER_LOOKBACK_DAYS
value: '7'
- name: FAIR_USE_CLASSIFIER_MODEL
value: gpt-5.1
- name: FAIR_USE_DAILY_SPEECH_MS
value: '7200000'
- name: FAIR_USE_ENABLED
value: 'false'
- name: FAIR_USE_EXEMPT_UIDS
value: ''
- name: FAIR_USE_KILL_SWITCH
value: 'false'
- name: FAIR_USE_REDIS_RETENTION_SECONDS
value: '691200'
- name: FAIR_USE_RESTRICT_DAILY_DG_MS
value: '1800000'
- name: FAIR_USE_WEEKLY_SPEECH_MS
value: '36000000'
- name: GOOGLE_CLOUD_PROJECT
value: based-hardware
- name: HOSTED_PUSHER_API_URL
value: http://internal-alb.pusher-ep-dev.il7.us-central1.lb.based-hardware-dev.internal
- name: HOSTED_SPEECH_PROFILE_API_URL
value: http://vad.omiapi.com:80/v1/speaker-identification
- name: HOSTED_VAD_API_URL
value: http://vad.omiapi.com:80/v1/vad
- name: HTTP_DEFAULT_TIMEOUT
value: '600'
- name: HTTP_GET_TIMEOUT
value: '30'
- name: LANGCHAIN_ENDPOINT
value: https://api.smith.langchain.com
- name: LANGCHAIN_PROJECT
value: development
- name: LANGCHAIN_TRACING_V2
value: 'true'
- name: NO_SOCKET_TIMEOUT
value: 'true'
- name: PINECONE_INDEX_NAME
value: memories-backend-dev
- name: REDIS_DB_PORT
value: '13151'
- name: TYPESENSE_HOST_PORT
value: '443'
- name: ADMIN_KEY
valueFrom:
secretKeyRef:
key: latest
name: ADMIN_KEY
- name: DEEPGRAM_API_KEY
valueFrom:
secretKeyRef:
key: latest
name: DEEPGRAM_API_KEY
- name: ENCRYPTION_SECRET
valueFrom:
secretKeyRef:
key: latest
name: ENCRYPTION_SECRET
- name: FAL_KEY
valueFrom:
secretKeyRef:
key: latest
name: FAL_KEY
- name: GITHUB_TOKEN
valueFrom:
secretKeyRef:
key: latest
name: GITHUB_TOKEN
- name: GOOGLE_APPLICATION_CREDENTIALS
valueFrom:
secretKeyRef:
key: latest
name: GOOGLE_APPLICATION_CREDENTIALS
- name: GOOGLE_MAPS_API_KEY
valueFrom:
secretKeyRef:
key: latest
name: GOOGLE_MAPS_API_KEY
- name: LANGCHAIN_API_KEY
valueFrom:
secretKeyRef:
key: latest
name: LANGCHAIN_API_KEY
- name: MARKETPLACE_APP_REVIEWERS
valueFrom:
secretKeyRef:
key: latest
name: MARKETPLACE_APP_REVIEWERS
- name: OPENAI_API_KEY
valueFrom:
secretKeyRef:
key: latest
name: OPENAI_API_KEY
- name: OPENROUTER_API_KEY
valueFrom:
secretKeyRef:
key: latest
name: OPENROUTER_API_KEY
- name: PINECONE_API_KEY
valueFrom:
secretKeyRef:
key: latest
name: PINECONE_API_KEY
- name: RAPID_API_HOST
valueFrom:
secretKeyRef:
key: latest
name: RAPID_API_HOST
- name: RAPID_API_KEY
valueFrom:
secretKeyRef:
key: latest
name: RAPID_API_KEY
- name: REDIS_DB_HOST
valueFrom:
secretKeyRef:
key: latest
name: REDIS_DB_HOST
- name: REDIS_DB_PASSWORD
valueFrom:
secretKeyRef:
key: latest
name: REDIS_DB_PASSWORD
- name: SERVICE_ACCOUNT_JSON
valueFrom:
secretKeyRef:
key: latest
name: SERVICE_ACCOUNT_JSON
- name: SONIOX_API_KEY
valueFrom:
secretKeyRef:
key: latest
name: SONIOX_API_KEY
- name: STRIPE_API_KEY
valueFrom:
secretKeyRef:
key: latest
name: STRIPE_API_KEY
- name: STRIPE_WEBHOOK_SECRET
valueFrom:
secretKeyRef:
key: latest
name: STRIPE_WEBHOOK_SECRET
- name: TYPESENSE_API_KEY
valueFrom:
secretKeyRef:
key: latest
name: TYPESENSE_API_KEY
- name: TYPESENSE_HOST
valueFrom:
secretKeyRef:
key: latest
name: TYPESENSE_HOST
- name: WORKFLOW_API_KEY
valueFrom:
secretKeyRef:
key: latest
name: WORKFLOW_API_KEY
image: gcr.io/based-hardware-dev/backend
name: backend-1
ports:
- containerPort: 8080
name: http1
resources:
limits:
cpu: 1000m
memory: 4Gi
startupProbe:
failureThreshold: 1
periodSeconds: 240
tcpSocket:
port: 8080
timeoutSeconds: 240
serviceAccountName: 1031333818730-compute@developer.gserviceaccount.com
timeoutSeconds: 300
traffic:
- latestRevision: true
percent: 100
Loading
Loading