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.
44 lines
2.3 KiB
Python
44 lines
2.3 KiB
Python
from pathlib import Path
|
|
|
|
from pydantic_settings import BaseSettings, SettingsConfigDict
|
|
|
|
# api/app/config.py -> repo root locally; "/" in the API image, where compose mounts /pipeline.
|
|
REPO_ROOT = Path(__file__).resolve().parents[2]
|
|
|
|
|
|
class Settings(BaseSettings):
|
|
model_config = SettingsConfigDict(env_file=".env", extra="ignore")
|
|
|
|
database_url: str = "postgresql+asyncpg://rarelens:rarelens@localhost:5432/rarelens"
|
|
# docker-compose publishes MLflow on 5001; macOS AirPlay Receiver owns 5000.
|
|
mlflow_tracking_uri: str = "http://localhost:5001"
|
|
model_name: str = "rarelens-pathogenicity"
|
|
# Registry alias set by `rarelens_ml.train --register` (stages are deprecated in MLflow 3).
|
|
model_alias: str = "production"
|
|
# A model artifact URI (gs://...) scores without an MLflow server running; wins over the registry.
|
|
model_uri: str | None = None
|
|
gcs_bucket: str | None = None # set in GCP; local uses ./data
|
|
pubsub_topic: str | None = None # "vcf-uploaded" in GCP; local runs pipeline inline
|
|
# Serverless track: run the Nextflow driver as a Cloud Run job instead of Argo + Pub/Sub.
|
|
cloudrun_job: str | None = None
|
|
gcp_project: str | None = None # required with pubsub_topic or cloudrun_job
|
|
gcp_region: str = "europe-west2"
|
|
pipeline_dir: Path = REPO_ROOT / "pipeline"
|
|
# Handed to the pipeline when it differs from the API's own: the loader runs inside a
|
|
# container, where the API's localhost would be the container itself.
|
|
pipeline_database_url: str | None = None
|
|
nextflow_profile: str = "docker"
|
|
# Local (non-gs://) VCFs must live under this directory.
|
|
local_data_root: Path = Path("/data")
|
|
# Browsers calling the API cross-origin; behind the ingress the UI is same-origin.
|
|
cors_origins: list[str] = ["http://localhost:5173"]
|
|
# Whether to keep pooled database connections open between requests. Set it false on a host
|
|
# that sleeps idle containers to save money -- Railway's serverless mode decides a service is
|
|
# idle from its *outbound* traffic, and a held connection is outbound traffic, so a pool keeps
|
|
# the service awake and billable forever. Costs a connection setup per request, which is
|
|
# nothing at demo traffic and the wrong trade under real load.
|
|
database_idle_connections: bool = True
|
|
|
|
|
|
settings = Settings()
|