Production Deployment (AWS App Runner) workflow (ansari-project/ansari-backend)
The Production Deployment (AWS App Runner) workflow from ansari-project/ansari-backend, explained and optimized by Latchkey.
CI health: C - fair
Point runs-on at Latchkey and get run de-duplication, job timeouts, SHA-pinned actions, self-healing for flaky steps, and up to 58% lower cost, applied automatically.
What it does
This is the Production Deployment (AWS App Runner) workflow from the ansari-project/ansari-backend repository, a real project running GitHub Actions. It is shown here with attribution under its MIT license.
Below, Latchkey shows a faster, safer version produced by its optimization engine.
The workflow
name: Production Deployment (AWS App Runner)
on:
push:
branches:
- main
workflow_dispatch:
jobs:
build-and-deploy:
runs-on: ubuntu-latest
environment: production-aws
steps:
- name: Checkout
uses: actions/checkout@v4
with:
persist-credentials: false
- name: Configure AWS credentials
id: aws-credentials
uses: aws-actions/configure-aws-credentials@v4
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ${{ secrets.AWS_REGION }}
- name: Login to Amazon ECR
id: login-ecr
uses: aws-actions/amazon-ecr-login@v2
- name: Build, tag, and push image to Amazon ECR
id: build-image
env:
ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
ECR_REPOSITORY: ansari-backend
IMAGE_TAG: ${{ github.sha }}
run: |
docker build -t $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG .
docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG
echo "::set-output name=image::$ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG"
- name: Deploy to App Runner
id: deploy-apprunner
uses: awslabs/amazon-app-runner-deploy@main
env:
DEPLOYMENT_TYPE: production
LOGGING_LEVEL: INFO
FRONTEND_URL: ${{ format('{0}{1}', secrets.SSM_ROOT, 'frontend-url') }}
MONGO_URL: ${{ format('{0}{1}', secrets.SSM_ROOT, 'mongo-url') }}
MONGO_DB_NAME: ${{ format('{0}{1}', secrets.SSM_ROOT, 'mongo-db-name') }}
SECRET_KEY: ${{ format('{0}{1}', secrets.SSM_ROOT, 'secret-key') }}
ORIGINS: ${{ format('{0}{1}', secrets.SSM_ROOT, 'origins') }}
OPENAI_API_KEY: ${{ format('{0}{1}', secrets.SSM_ROOT, 'openai-api-key') }}
SENDGRID_API_KEY: ${{ format('{0}{1}', secrets.SSM_ROOT, 'sendgrid-api-key') }}
MAILCHIMP_API_KEY: ${{ format('{0}{1}', secrets.SSM_ROOT, 'mailchimp-api-key') }}
MAILCHIMP_SERVER_PREFIX: ${{ format('{0}{1}', secrets.SSM_ROOT, 'mailchimp-server-prefix') }}
MAILCHIMP_LIST_ID: ${{ format('{0}{1}', secrets.SSM_ROOT, 'mailchimp-list-id') }}
ANTHROPIC_API_KEY: ${{ format('{0}{1}', secrets.SSM_ROOT, 'anthropic-api-key') }}
KALEMAT_API_KEY: ${{ format('{0}{1}', secrets.SSM_ROOT, 'kalemat-api-key') }}
SUNNAH_TOKEN: ${{ format('{0}{1}', secrets.SSM_ROOT, 'sunnah-token') }}
VECTARA_API_KEY: ${{ format('{0}{1}', secrets.SSM_ROOT, 'vectara-api-key') }}
QURAN_DOT_COM_API_KEY: ${{ format('{0}{1}', secrets.SSM_ROOT, 'quran-dot-com-api-key') }}
USUL_API_TOKEN: ${{ format('{0}{1}', secrets.SSM_ROOT, 'usul-api-token') }}
SENTRY_DSN: ${{ format('{0}{1}', secrets.SSM_ROOT, 'sentry-dsn') }}
WHATSAPP_SERVICE_API_KEY: ${{ format('{0}{1}', secrets.SSM_ROOT, 'whatsapp-service-api-key') }}
WHATSAPP_ACCESS_TOKEN_FROM_SYS_USER: ${{ format('{0}{1}', secrets.SSM_ROOT, 'whatsapp-access-token-from-sys-user') }}
WHATSAPP_BUSINESS_PHONE_NUMBER_ID: ${{ format('{0}{1}', secrets.SSM_ROOT, 'whatsapp-business-phone-number-id') }}
WHATSAPP_VERIFY_TOKEN_FOR_WEBHOOK: ${{ format('{0}{1}', secrets.SSM_ROOT, 'whatsapp-verify-token-for-webhook') }}
WHATSAPP_ENABLED: ${{ format('{0}{1}', secrets.SSM_ROOT, 'whatsapp-enabled') }}
WHATSAPP_API_VERSION: ${{ format('{0}{1}', secrets.SSM_ROOT, 'whatsapp-api-version') }}
WHATSAPP_CHAT_RETENTION_HOURS: ${{ format('{0}{1}', secrets.SSM_ROOT, 'whatsapp-chat-retention-hours') }}
MAINTENANCE_MODE: ${{ format('{0}{1}', secrets.SSM_ROOT, 'maintenance-mode') }}
IOS_MINIMUM_BUILD_VERSION: ${{ format('{0}{1}', secrets.SSM_ROOT, 'ios-minimum-build-version') }}
IOS_LATEST_BUILD_VERSION: ${{ format('{0}{1}', secrets.SSM_ROOT, 'ios-latest-build-version') }}
ANDROID_MINIMUM_BUILD_VERSION: ${{ format('{0}{1}', secrets.SSM_ROOT, 'android-minimum-build-version') }}
ANDROID_LATEST_BUILD_VERSION: ${{ format('{0}{1}', secrets.SSM_ROOT, 'android-latest-build-version') }}
with:
service: ansari-production-backend
image: ${{ steps.build-image.outputs.image }}
access-role-arn: ${{ secrets.SERVICE_ROLE_ARN }}
region: ${{ secrets.AWS_REGION }}
cpu : 1
memory : 2
port: 8000
wait-for-service-stability-seconds: 1200
copy-env-vars: |
DEPLOYMENT_TYPE
LOGGING_LEVEL
copy-secret-env-vars: |
FRONTEND_URL
MONGO_URL
MONGO_DB_NAME
SECRET_KEY
ORIGINS
OPENAI_API_KEY
SENDGRID_API_KEY
MAILCHIMP_API_KEY
MAILCHIMP_SERVER_PREFIX
MAILCHIMP_LIST_ID
ANTHROPIC_API_KEY
KALEMAT_API_KEY
SUNNAH_TOKEN
VECTARA_API_KEY
QURAN_DOT_COM_API_KEY
USUL_API_TOKEN
SENTRY_DSN
WHATSAPP_SERVICE_API_KEY
WHATSAPP_ACCESS_TOKEN_FROM_SYS_USER
WHATSAPP_BUSINESS_PHONE_NUMBER_ID
WHATSAPP_VERIFY_TOKEN_FOR_WEBHOOK
WHATSAPP_API_VERSION
WHATSAPP_ENABLED
WHATSAPP_CHAT_RETENTION_HOURS
MAINTENANCE_MODE
IOS_MINIMUM_BUILD_VERSION
IOS_LATEST_BUILD_VERSION
ANDROID_MINIMUM_BUILD_VERSION
ANDROID_LATEST_BUILD_VERSION
instance-role-arn: ${{ secrets.INSTANCE_ROLE_ARN }}
- name: App Runner URL
run: echo "App runner URL ${{ steps.deploy-apprunner.outputs.service-url }}"
The same workflow, on Latchkey
Removes redundant runs and caps runaway jobs. Added and changed lines are highlighted.
name: Production Deployment (AWS App Runner) on: push: branches: - main workflow_dispatch: concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true jobs: build-and-deploy: timeout-minutes: 30 runs-on: latchkey-small environment: production-aws steps: - name: Checkout uses: actions/checkout@v4 with: persist-credentials: false - name: Configure AWS credentials id: aws-credentials uses: aws-actions/configure-aws-credentials@v4 with: aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} aws-region: ${{ secrets.AWS_REGION }} - name: Login to Amazon ECR id: login-ecr uses: aws-actions/amazon-ecr-login@v2 - name: Build, tag, and push image to Amazon ECR id: build-image env: ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }} ECR_REPOSITORY: ansari-backend IMAGE_TAG: ${{ github.sha }} run: | docker build -t $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG . docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG echo "::set-output name=image::$ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG" - name: Deploy to App Runner id: deploy-apprunner uses: awslabs/amazon-app-runner-deploy@main env: DEPLOYMENT_TYPE: production LOGGING_LEVEL: INFO FRONTEND_URL: ${{ format('{0}{1}', secrets.SSM_ROOT, 'frontend-url') }} MONGO_URL: ${{ format('{0}{1}', secrets.SSM_ROOT, 'mongo-url') }} MONGO_DB_NAME: ${{ format('{0}{1}', secrets.SSM_ROOT, 'mongo-db-name') }} SECRET_KEY: ${{ format('{0}{1}', secrets.SSM_ROOT, 'secret-key') }} ORIGINS: ${{ format('{0}{1}', secrets.SSM_ROOT, 'origins') }} OPENAI_API_KEY: ${{ format('{0}{1}', secrets.SSM_ROOT, 'openai-api-key') }} SENDGRID_API_KEY: ${{ format('{0}{1}', secrets.SSM_ROOT, 'sendgrid-api-key') }} MAILCHIMP_API_KEY: ${{ format('{0}{1}', secrets.SSM_ROOT, 'mailchimp-api-key') }} MAILCHIMP_SERVER_PREFIX: ${{ format('{0}{1}', secrets.SSM_ROOT, 'mailchimp-server-prefix') }} MAILCHIMP_LIST_ID: ${{ format('{0}{1}', secrets.SSM_ROOT, 'mailchimp-list-id') }} ANTHROPIC_API_KEY: ${{ format('{0}{1}', secrets.SSM_ROOT, 'anthropic-api-key') }} KALEMAT_API_KEY: ${{ format('{0}{1}', secrets.SSM_ROOT, 'kalemat-api-key') }} SUNNAH_TOKEN: ${{ format('{0}{1}', secrets.SSM_ROOT, 'sunnah-token') }} VECTARA_API_KEY: ${{ format('{0}{1}', secrets.SSM_ROOT, 'vectara-api-key') }} QURAN_DOT_COM_API_KEY: ${{ format('{0}{1}', secrets.SSM_ROOT, 'quran-dot-com-api-key') }} USUL_API_TOKEN: ${{ format('{0}{1}', secrets.SSM_ROOT, 'usul-api-token') }} SENTRY_DSN: ${{ format('{0}{1}', secrets.SSM_ROOT, 'sentry-dsn') }} WHATSAPP_SERVICE_API_KEY: ${{ format('{0}{1}', secrets.SSM_ROOT, 'whatsapp-service-api-key') }} WHATSAPP_ACCESS_TOKEN_FROM_SYS_USER: ${{ format('{0}{1}', secrets.SSM_ROOT, 'whatsapp-access-token-from-sys-user') }} WHATSAPP_BUSINESS_PHONE_NUMBER_ID: ${{ format('{0}{1}', secrets.SSM_ROOT, 'whatsapp-business-phone-number-id') }} WHATSAPP_VERIFY_TOKEN_FOR_WEBHOOK: ${{ format('{0}{1}', secrets.SSM_ROOT, 'whatsapp-verify-token-for-webhook') }} WHATSAPP_ENABLED: ${{ format('{0}{1}', secrets.SSM_ROOT, 'whatsapp-enabled') }} WHATSAPP_API_VERSION: ${{ format('{0}{1}', secrets.SSM_ROOT, 'whatsapp-api-version') }} WHATSAPP_CHAT_RETENTION_HOURS: ${{ format('{0}{1}', secrets.SSM_ROOT, 'whatsapp-chat-retention-hours') }} MAINTENANCE_MODE: ${{ format('{0}{1}', secrets.SSM_ROOT, 'maintenance-mode') }} IOS_MINIMUM_BUILD_VERSION: ${{ format('{0}{1}', secrets.SSM_ROOT, 'ios-minimum-build-version') }} IOS_LATEST_BUILD_VERSION: ${{ format('{0}{1}', secrets.SSM_ROOT, 'ios-latest-build-version') }} ANDROID_MINIMUM_BUILD_VERSION: ${{ format('{0}{1}', secrets.SSM_ROOT, 'android-minimum-build-version') }} ANDROID_LATEST_BUILD_VERSION: ${{ format('{0}{1}', secrets.SSM_ROOT, 'android-latest-build-version') }} with: service: ansari-production-backend image: ${{ steps.build-image.outputs.image }} access-role-arn: ${{ secrets.SERVICE_ROLE_ARN }} region: ${{ secrets.AWS_REGION }} cpu : 1 memory : 2 port: 8000 wait-for-service-stability-seconds: 1200 copy-env-vars: | DEPLOYMENT_TYPE LOGGING_LEVEL copy-secret-env-vars: | FRONTEND_URL MONGO_URL MONGO_DB_NAME SECRET_KEY ORIGINS OPENAI_API_KEY SENDGRID_API_KEY MAILCHIMP_API_KEY MAILCHIMP_SERVER_PREFIX MAILCHIMP_LIST_ID ANTHROPIC_API_KEY KALEMAT_API_KEY SUNNAH_TOKEN VECTARA_API_KEY QURAN_DOT_COM_API_KEY USUL_API_TOKEN SENTRY_DSN WHATSAPP_SERVICE_API_KEY WHATSAPP_ACCESS_TOKEN_FROM_SYS_USER WHATSAPP_BUSINESS_PHONE_NUMBER_ID WHATSAPP_VERIFY_TOKEN_FOR_WEBHOOK WHATSAPP_API_VERSION WHATSAPP_ENABLED WHATSAPP_CHAT_RETENTION_HOURS MAINTENANCE_MODE IOS_MINIMUM_BUILD_VERSION IOS_LATEST_BUILD_VERSION ANDROID_MINIMUM_BUILD_VERSION ANDROID_LATEST_BUILD_VERSION instance-role-arn: ${{ secrets.INSTANCE_ROLE_ARN }} - name: App Runner URL run: echo "App runner URL ${{ steps.deploy-apprunner.outputs.service-url }}"
What changed
- Run on Latchkey managed runners with one line (
runs-on), which apply the fixes below automatically and self-heal transient failures. This example useslatchkey-small; pick the runner size that fits the job. - Cancel superseded runs when a branch or PR gets a newer push.
- Add a job timeout so a hung step cannot burn hours of runner time.
3 third-party actions are referenced by a movable tag. Pin them to the commit SHA (Latchkey resolves and applies this automatically) so a repointed tag cannot change what runs.
What Latchkey heals here
This workflow has steps that commonly fail on transient issues (network, registries, flaky browsers). On Latchkey managed runners they are detected, retried, and self-healed instead of failing your build:
- Container pulls and builds
This workflow runs 1 job per trigger. On Latchkey the same minutes cost up to 58% less than GitHub-hosted, with zero queue time.