Table of Contents
Deployments
Three ways to run it. Pick on cost and on whether you need the pipeline.
| Pipeline runs? | Idle cost | Effort | |
|---|---|---|---|
| GCP serverless | yes | ~£1/month | terraform apply |
| GCP Kubernetes | yes | control plane + Cloud SQL | flag, then destroy |
| Railway | no | $5/month flat | railway up |
GCP serverless (default)
cd infra/terraform
terraform init -backend-config="bucket=<tfstate bucket>"
export TF_VAR_database_url='postgresql+asyncpg://user:pass@host/db?sslmode=require'
terraform apply -var project=<project id>
cd ../.. && make serverless-deploy PROJECT=<project id> TAG=<commit sha>
terraform output web_url is the address to share: it serves the UI and proxies /api, so there
is one public address and no CORS. Upload the VEP cache to gs://<project>-rarelens-data/refs/vep
before a real annotation, and set -var model_uri=gs://.../models/pathogenicity/1 to score without
an MLflow server.
Set a billing budget first. The demo has no authentication.
Railway
Three services — Postgres, api, web — with the API on the private network only, so the UI's /api
proxy is the single public entry point.
railway link --project <id> --environment production --service api
cd api && railway up --service api # the repo is on Gitea, so deploy from the working copy
cd ../web && railway up --service web
Variables: on the API, DATABASE_URL pointing at postgres.railway.internal and
DATABASE_IDLE_CONNECTIONS=false; on the UI, API_INTERNAL_URL=http://api.railway.internal:8000,
PUBLIC_PIPELINE_ENABLED=false, BASIC_AUTH_USER and BASIC_AUTH_PASSWORD.
Three things to know:
- The pipeline cannot run there. Nextflow shells out to
docker runfor VEP and bcftools, and a container platform gives you a container, not a Docker daemon. Cases are annotated elsewhere and copied up withscripts/seed-remote.sh;PUBLIC_PIPELINE_ENABLED=falsehides the buttons that would otherwise be left to fail. DATABASE_IDLE_CONNECTIONS=falseis what makes sleeping work. Railway decides a service is idle from its outbound traffic, and a pooled database connection is outbound traffic, so the default pool keeps the service awake and billable for ever. It usesNullPoolinstead — a connection per request, which is nothing at demo traffic and the wrong trade under real load.- Serverless must be enabled per service and only applies on the next deploy. Leave it off for Postgres, which holds the volume. Expect the documented 502 on the first request to a slept service; it answers on retry.
Seeding a remote database
scripts/seed-remote.sh "postgresql://user:pass@host:port/db"
Copies the analysed cases and the HPO reference data. --data-only: the target's schema comes from
Alembic, so the two cannot disagree about it. Run alembic upgrade head against the target first.
rarelens
Understanding it
Working on it
Running it
When it goes wrong