Three services -- Postgres, API, UI -- with the API on Railway's private network only, so the UI's /api proxy is the single public entry point and there is no CORS. The pipeline cannot run there. Nextflow shells out to `docker run` for VEP and bcftools, and Railway gives you a container, not a Docker daemon. Rather than leave a button that always fails, cases are annotated locally and copied up by scripts/seed-remote.sh, and PUBLIC_PIPELINE_ENABLED=false hides the analyse/score actions and the create-case form. DATABASE_IDLE_CONNECTIONS=false is what makes idling work. Railway decides a service is idle from its *outbound* traffic and sleeps it after ~5-10 minutes; a pooled database connection is outbound traffic, so SQLAlchemy's default pool would have kept the API awake and billable for ever. Setting it false switches to NullPool, which costs a connection per request -- nothing at demo traffic, the wrong trade under real load, hence the flag rather than a rewrite. BASIC_AUTH_USER / BASIC_AUTH_PASSWORD put one shared credential in front of the site. Nothing deployed is patient data, so this stops the URL being wandered into rather than protecting anyone's privacy; unset, the site is open, which is what local development wants. Compared in constant time, and both halves of the credential are checked even when the first fails.
61 lines
2.7 KiB
Bash
Executable File
61 lines
2.7 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Copy the analysed demo cases and the HPO reference data into a remote database.
|
|
#
|
|
# The deployed demo has no Nextflow and no Docker daemon, so it cannot run VEP. Instead the cases
|
|
# are annotated here, where the pipeline works, and the results are copied up. Visitors get real
|
|
# analysed cases -- funnel, ranking, evidence, decisions, report -- against a database that is
|
|
# never asked to produce them.
|
|
#
|
|
# Everything copied is derived from public, openly licensed sources (docs/data.md). There is no
|
|
# patient data in this dump, and there must never be.
|
|
#
|
|
# scripts/seed-remote.sh "$(railway variables -s Postgres --kv | grep DATABASE_PUBLIC_URL | cut -d= -f2-)"
|
|
set -euo pipefail
|
|
|
|
TARGET=${1:-${TARGET_DATABASE_URL:-}}
|
|
SOURCE=${SOURCE_DATABASE_URL:-postgresql://rarelens:rarelens@localhost:5432/rarelens}
|
|
IMAGE=${PG_IMAGE:-postgres:16-alpine}
|
|
|
|
# Reference data first, then a case's own rows: variants reference jobs, jobs reference cases.
|
|
TABLES=(hpo_terms gene_phenotypes cases case_phenotypes jobs variants predictions variant_decisions)
|
|
|
|
if [ -z "$TARGET" ]; then
|
|
echo "usage: $0 <target postgres URL> (or set TARGET_DATABASE_URL)" >&2
|
|
echo "the target must already have the schema: run 'alembic upgrade head' against it first" >&2
|
|
exit 2
|
|
fi
|
|
|
|
case "$TARGET" in
|
|
postgres://*|postgresql://*) ;;
|
|
*) echo "target must be a postgres:// URL, got ${TARGET%%:*}:..." >&2; exit 2 ;;
|
|
esac
|
|
|
|
echo "==> source: ${SOURCE%%\?*}" >&2
|
|
echo "==> target: ${TARGET%%:*}://…${TARGET##*@}" >&2 # host only: the password stays out of the log
|
|
echo "==> tables: ${TABLES[*]}" >&2
|
|
|
|
# --data-only: the target's schema comes from Alembic, so the two can never disagree about it.
|
|
# Truncating first makes the script repeatable; cascade because variants hang off jobs.
|
|
docker run --rm -i --add-host=host.docker.internal:host-gateway \
|
|
-e PGPASSWORD_UNUSED=1 "$IMAGE" \
|
|
pg_dump --data-only --no-owner --no-privileges \
|
|
$(printf -- '--table=%s ' "${TABLES[@]}") \
|
|
"${SOURCE/localhost/host.docker.internal}" \
|
|
> /tmp/rarelens-seed.sql
|
|
|
|
lines=$(wc -l < /tmp/rarelens-seed.sql)
|
|
echo "==> dumped $lines lines" >&2
|
|
|
|
docker run --rm -i "$IMAGE" psql "$TARGET" -v ON_ERROR_STOP=1 \
|
|
-c "TRUNCATE $(IFS=,; echo "${TABLES[*]}") RESTART IDENTITY CASCADE" >&2
|
|
|
|
docker run --rm -i "$IMAGE" psql "$TARGET" -v ON_ERROR_STOP=1 -q < /tmp/rarelens-seed.sql
|
|
rm -f /tmp/rarelens-seed.sql
|
|
|
|
echo "==> loaded. counts on the target:" >&2
|
|
docker run --rm -i "$IMAGE" psql "$TARGET" -At -c "
|
|
select 'cases: '||count(*) from cases
|
|
union all select 'variants: '||count(*) from variants
|
|
union all select 'gene_phenotypes: '||count(*) from gene_phenotypes
|
|
union all select 'hpo_terms: '||count(*) from hpo_terms"
|