agilentics / boiler
# App Engine standard - the PRODUCTION service.
#
# No password is committed here. DB_PASS and SECRET_KEY come from
# env_secrets.yaml, which is gitignored and rendered at deploy time from CI
# secrets (see env_secrets.yaml.example for the shape).
runtime: python310

service: default

# F1 is 600 MHz / 384 MiB and is the cheapest class. Measure before moving up:
# a faster core relieves nothing if the app is waiting on the database rather
# than burning CPU, and raising max_instances is the cheaper lever because it is
# billed only when the instances actually run.
instance_class: F1

automatic_scaling:
  # Keep one instance warm so the app never cold-starts. Without this, App Engine
  # scales to zero when idle and the next request pays a cold start; the worst
  # case is a user returning from an external redirect (a payment provider, an
  # OAuth consent screen) hitting the instance mid-boot and getting an "upstream
  # connect error" from the load balancer.
  min_instances: 1
  # This number, WEB_THREADS, WEB_CONCURRENCY and the pool size in
  # utils/db_wrapper.py are ONE decision:
  #
  #     (pool_size + max_overflow) x WEB_CONCURRENCY x max_instances
  #
  # must fit inside the Cloud SQL instance's max_connections (100 by default),
  # minus whatever else shares that instance. At the defaults this is
  # (4+1) x 2 x 4 = 40. Raising this alone is what exhausts the database.
  max_instances: 4

entrypoint: gunicorn -c gunicorn.py main:app

includes:
  - env_secrets.yaml

# Mounts /cloudsql/<connection_name>. The deploy service account needs
# roles/cloudsql.client on the instance.
beta_settings:
  cloud_sql_instances: myapp-000000:us-central1:myapp-postgres

env_variables:
  # "prod" means "deployed behind HTTPS", not "the production environment": it is
  # what sets SESSION_COOKIE_SECURE and arms the weak-SECRET_KEY guard in main.py.
  ENV: prod
  DB_USER: myapp
  DB_NAME: myapp
  INSTANCE_UNIX_SOCKET: myapp-000000:us-central1:myapp-postgres

  # The canonical public origin. Security-sensitive external links (password
  # reset, email verification, a payment provider's return URL) are built from
  # it, so they point here rather than at whatever host a request arrived on.
  PUBLIC_BASE_URL: https://myapp.example.com

  # Outbound email. Non-secret config lives here; the mailbox password is
  # SMTP_PASS in env_secrets.yaml. Delete these four lines to deploy with mail
  # logged instead of sent.
  # SMTP_HOST: mail.example.com
  # SMTP_PORT: "587"
  # SMTP_USER: noreply@myapp.example.com
  # SMTP_FROM: noreply@myapp.example.com

handlers:
- url: /static
  static_dir: static
- url: /.*
  secure: always
  redirect_http_response_code: 301
  script: auto