Skip to content

Commit 6dd24c8

Browse files
committed
Update deployment notes with Railway as recommended approach
Incorporates findings from discussion: ephemeral containers, no persistent storage needed, 100+ concurrent participants, programmatic lifecycle via Railway GraphQL API, management server architecture. https://claude.ai/code/session_01Bzh4jnE9BfaPyoWyP2FVjs
1 parent 0446741 commit 6dd24c8

1 file changed

Lines changed: 58 additions & 16 deletions

File tree

deploy/DEPLOYMENT-ALTERNATIVES.md

Lines changed: 58 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -5,38 +5,80 @@ AWS + Terraform (in [deliberation-infrastructure](https://github.com/Watts-Lab/d
55

66
## Requirements
77
- Spin up ephemeral containers on-demand (per study, lasting a few hours)
8-
- Tear down after study completes and data is saved
8+
- One container per experiment — no load balancing, the single server must handle all participants
9+
- Up to 100+ concurrent participants per study
10+
- Tear down after study completes and data is exported
911
- Programmatic creation/destruction (API-driven, not manual)
1012
- Multiple concurrent studies on different subdomains
1113
- WebSocket support (Empirica requires it)
1214
- Container runs on port 3000, needs env vars for external services (Daily, Qualtrics, Etherpad, GitHub)
13-
- Data export happens via postFlight (pushes to GitHub) — Tajriba state may not need to survive container
15+
- Data export happens via postFlight (pushes to GitHub) — Tajriba state does not need to survive container
16+
- Researcher or management server signals "study is done"; fallback 12hr TTL auto-teardown
1417

15-
## Platform Options
18+
## Recommended Approach: Railway + Management Server
19+
20+
### Why Railway
21+
- Already have familiarity/account
22+
- Full GraphQL API (`https://backboard.railway.com/graphql/v2`) for programmatic service lifecycle
23+
- Docker image deploys from GHCR — no rebuild needed
24+
- WebSocket support out of the box
25+
- Services stay running until explicitly deleted (no unwanted auto-suspend)
26+
- Pro plan supports up to 32GB RAM / 8 vCPU per service
27+
- Per-minute billing; a few-hour study on 2GB/1vCPU costs ~$0.01-0.05
28+
- Custom subdomains via API, or wildcard domain (`*.studies.yourdomain.com`)
29+
30+
### API Flow (per study)
31+
32+
1. **Create service**`serviceCreate` mutation with `source.image` pointing to GHCR image
33+
2. **Set env vars**`variableUpsert` for DAILY_APIKEY, QUALTRICS_API_TOKEN, SUBDOMAIN, etc.
34+
3. **Attach domain**`customDomainCreate` for `study-xyz.yourdomain.com`
35+
4. **Wait for deployment** — service starts automatically after creation
36+
5. **Tear down**`serviceDelete` when researcher signals done or TTL expires
37+
38+
### Management Server Architecture
39+
40+
```
41+
[Researcher UI] → [Management Server (always-on Railway service)]
42+
|
43+
├── Railway GraphQL API (create/delete study services)
44+
├── SQLite/Postgres (tracks active studies, TTLs, researcher info)
45+
└── Timer/cron (reaps studies past 12hr TTL)
46+
```
47+
48+
The management server is a single small always-on service in the same Railway project.
49+
50+
### Sizing Guide
51+
| Study size | Recommended tier | Approx. cost/hr |
52+
|------------------|-------------------|------------------|
53+
| < 30 participants | 1GB RAM / shared CPU | ~$0.005 |
54+
| 30–100 participants | 2GB RAM / 1 vCPU | ~$0.01 |
55+
| 100+ participants | 4GB RAM / 2 vCPU | ~$0.03 |
56+
57+
Video load is handled by Daily.co, not the study server — Empirica just manages lightweight JSON state sync over WebSocket.
58+
59+
### References
60+
- [Railway API Cookbook](https://docs.railway.com/guides/api-cookbook)
61+
- [Manage Services API](https://docs.railway.com/guides/manage-services)
62+
- [Railway Public API](https://docs.railway.com/guides/public-api)
63+
- [Railway Domains](https://docs.railway.com/networking/domains)
64+
65+
## Other Options Considered
1666

1767
### Fly.io Machines API
1868
- REST API for create/start/stop/destroy machines
19-
- Auto-suspend idle machines, auto-start on request
69+
- Auto-suspend idle machines, auto-start on request (not wanted — we need always-on)
2070
- Per-second billing, no cost when stopped
2171
- Good CLI for scripting
72+
- Would also work well, but less familiar
2273

2374
### AWS ECS Fargate (simplify existing AWS)
2475
- Replace Terraform with a thin API calling `RunTask` / `StopTask`
2576
- No EC2 management, pay-per-second
2677
- Keeps existing container registry (GHCR) and AWS account
78+
- Still more complex than Railway
2779

2880
### Google Cloud Run
29-
- Push image, API to spin up/tear down services per study
30-
- Auto-scales to zero
31-
- Simple API
81+
- Auto-scales to zero — not suitable for long-running WebSocket sessions
3282

3383
### Modal / Beam
34-
- Designed for ephemeral container workloads
35-
- Least code to wire up
36-
- May have limitations for long-running (multi-hour) WebSocket containers
37-
38-
## Open Questions
39-
1. Does Tajriba state need to survive the container, or is the GitHub export the source of truth?
40-
2. How does "study is done" get signaled? Empirica callback, or researcher clicks "shut down"?
41-
3. How many concurrent studies at peak?
42-
4. Who requests the server — team researchers or external users needing auth?
84+
- Designed for short-lived workloads — may not support multi-hour WebSocket containers well

0 commit comments

Comments
 (0)