# App Engine standard - the INTEGRATION service.
#
# Deployed to the same project as production and alongside it, as a second
# service rather than a second project: `gcloud app deploy app-int.yaml`. The
# `default` service is untouched by that command, so production keeps serving
# whatever it was serving.
#
# What differs from app.yaml, and why each difference exists, is the whole
# content of this file. Everything not listed here is deliberately the same, so
# int is a rehearsal of production rather than a different application.
runtime: python310
# The one line that makes this a separate deployment. The hostname follows from
# it: https://int-dot-<project>.<region>.r.appspot.com
service: int
instance_class: F1
automatic_scaling:
# No warm instance. Production keeps one because a user returning from an
# external redirect must not meet a cold start; nobody is waiting on int, and
# an always-on instance would bill for a service that is idle almost always.
min_instances: 0
# One, against a budget rather than against demand: int's share of the shared
# Cloud SQL instance is whatever production does not account for. With the two
# numbers below that is (2 threads + 1 overflow) x 1 worker x 1 instance = 3
# connections. These four numbers are one decision - see app.yaml.
max_instances: 1
entrypoint: gunicorn -c gunicorn.py main:app
# Its own secret file, not production's. Rendered by CI into the runner's
# workspace and gitignored, exactly like env_secrets.yaml - and separate so that
# int cannot pick up production's secrets by including the wrong file.
includes:
- env_secrets_int.yaml
beta_settings:
cloud_sql_instances: myapp-000000:us-central1:myapp-postgres
env_variables:
# "prod" because int is served over HTTPS like everything else - anything else
# here would hand out session cookies without the Secure flag. It does not mean
# "the production environment".
ENV: prod
DB_USER: myapp
# The only difference that matters. A separate database on the same instance,
# created with `gcloud sql databases create myapp_int`.
DB_NAME: myapp_int
INSTANCE_UNIX_SOCKET: myapp-000000:us-central1:myapp-postgres
# See max_instances above - these three numbers are one decision.
WEB_CONCURRENCY: "1"
WEB_THREADS: "2"
PUBLIC_BASE_URL: https://int-dot-myapp-000000.uc.r.appspot.com
# Deliberately absent, and each absence is a behaviour:
#
# SMTP_* mail is logged instead of sent, so int cannot email a
# real person a verification or reset link.
# GOOGLE_CLIENT_* no Google sign-in; the button is hidden and password
# sign-in still works. A passkey or an OAuth client is
# bound to the origins registered for it, so production's
# client does not cover the int hostname - register
# <this host>/auth/google/callback on it to switch this on.
#
# Add to this list as you add integrations, and say what the absence does
# rather than leaving a reader to infer it from settings.py.
handlers:
- url: /static
static_dir: static
- url: /.*
secure: always
redirect_http_response_code: 301
script: auto