Relay · Operations
部署與操作
Relay 提供 application runtime contract,不是 managed service。Repository 可以 build Elixir release 與 multi-stage container image。Image publication、PostgreSQL、R2、TLS termination、secret、backup、rollout、rollback 與 alerting 都由 deployment operator 負責。
Runtime dependency
| Dependency | Contract |
|---|---|
| PostgreSQL 18 以上 | 儲存 public registry、per-tenant schema、Oban job、handoff、audit row 與 default search index。需要原生 uuidv7()。 |
| Cloudflare R2-compatible storage | 儲存 message attachment。使用 default storage client 時,production runtime 目前要求完整 R2 credential。 |
| HTTP 與 WebSocket proxy | 必須保留 Phoenix WebSocket upgrade 與 forwarded HTTPS scheme。 |
| OTLP collector | Optional operational dependency。Runtime default trace exporter endpoint 是 http://localhost:4318。 |
Postgres FTS 需要 pg_trgm。中文 segmentation 建議使用 zhparser,但不是必要條件。無法使用時,Relay 會 fallback 至 simple_bigram、記錄 warning,並將受影響的 search response 標成 degraded。
Production 必要設定
| Variable | 用途 |
|---|---|
DATABASE_URL | PostgreSQL connection URL |
SECRET_KEY_BASE | Phoenix signing 與 encryption secret |
CLOAK_KEY | 用於 tenant secret 的 base64-encoded 32-byte AES-GCM key |
PHX_SERVER=true | 在 Elixir release 內啟動 HTTP server |
ADMIN_TOKEN | 保護 /api/admin/*;缺少時,admin API request 無法通過 authentication |
TONETIFY_RELAY_CORS_ORIGINS | 逗號分隔的 browser origin;production value 為空時,cross-origin request 會 fail closed |
R2_ENDPOINT | R2 account endpoint |
R2_BUCKET | Attachment bucket |
R2_ACCESS_KEY_ID | Bucket-scoped access key |
R2_SECRET_ACCESS_KEY | Bucket-scoped secret |
常見 optional setting 包含 PORT、PHX_HOST、POOL_SIZE、DNS_CLUSTER_QUERY、METRICS_TOKEN、OTEL_EXPORTER_OTLP_ENDPOINT、TONETIFY_RELAY_WEBHOOK_URL、TONETIFY_RELAY_WEBHOOK_SECRET、upload 與 download URL TTL,以及 SEARCH_CHINESE_MODE。
所有 exposed production environment 都應設定 METRICS_TOKEN。未設定時,/metrics 沒有 application-layer authentication。即使已設定 token,也應以 network policy 限制 endpoint。
不能記錄 ADMIN_TOKEN、CLOAK_KEY、R2 credential、host webhook secret、host-sync Basic credential、tenant JWT secret,或 presigned attachment URL。
Build 與 start
Repository 包含 server/Dockerfile,會 build Mix release 並啟動 bin/chataas。Non-container deployment 可以直接執行同一份 release:
PHX_SERVER=true bin/chataas start Repository 目前不會 publish versioned image,也沒有 supported Compose stack 或 platform-neutral deployment manifest。Dockerfile 是 build input,不是已發行的 product artifact。
Migration
新 release 接收流量前,先執行 migration:
bin/chataas eval "Chataas.Release.migrate()" 這個 entrypoint 會套用 public-schema migration、找出每個 tenant_% schema,再逐一套用 tenant migration。Migration traffic 應使用 direct PostgreSQL connection,或確定支援 DDL 與 advisory behavior 的 pool mode。
舊版與新版 application 可能重疊時,schema change 應使用 forward-compatible expand 與 contract 流程。Runtime 包含 public-schema rollback function,但沒有同時涵蓋 public 與 tenant schema 的完整 automated rollback contract。Restore rehearsal 與 downgrade compatibility 仍由 operator 負責。
Health 與 deploy gate
| Endpoint | 意義 |
|---|---|
GET /livez | 不檢查 dependency 的 process liveness |
GET /health | Liveness 的 legacy alias |
GET /ready 或 GET /readyz | 對 primary database 執行 SELECT 1,unavailable 時回傳 503 |
最小 deployment gate:
curl -fsS "$BASE_URL/health"
curl -fsS "$BASE_URL/ready"
curl -fsS "$BASE_URL/api/channels" \
-H "Authorization: Bearer $TENANT_USER_JWT" 接著使用 real WebSocket client,join tonetify-relay:<tenant_id>:<channel_id>、以 unique nonce 傳送 msg:send,並確認 acknowledgement 包含 id 與 seq。只有 liveness 與 readiness,不能證明 tenant migration、authentication、fan-out 或 message delivery 正常。
Worker 與 durable handoff
Relay 使用 Oban queue 執行 WebSocket fan-out、host webhook、adapter egress、user export、governance cleanup、R2 deletion 與 search reindex。Message side effect 會先寫入 public.post_commit_handoffs,再由各 sink worker drain。
Periodic poller 會在 best-effort immediate wakeup 失效後維持 correctness。Stale processing claim 的 default recovery threshold 是五分鐘。dispatch_seq 用於 handoff claim ordering;message order 仍以 channel-local messages.seq 為準。
Operator 應監控 queue availability、retry exhaustion、oldest pending handoff age、per-sink backlog、webhook dead letter、R2 deletion failure、reindex status 與 database pool saturation。HTTP process healthy 時,delivery backlog 仍可能持續增加。
Metrics 與 trace
GET /metrics 會暴露 Phoenix、Ecto、VM、business event、search、R2 與 post-commit handoff series。重要 signal 包含:
- send、edit、retract 與 delete success throughput;
- join 與 catch-up activity;
- WebSocket 與 HTTP error bucket;
- handoff transition count 與 backlog gauge;
- search、webhook 與 object-deletion failure。
Typing 是 best-effort,不屬於 durable delivery 或 business metric。Reconnect metric 代表帶有 last_seq 的 successful join,不是每一次 lower-level socket reconnect。
Relay 透過 OTLP 發出 OpenTelemetry trace。Repository 目前沒有提供 dashboard、alert threshold、paging policy 或 service objective 等 supported product package。
Backup 與 recovery boundary
PostgreSQL 與 attachment bucket 應視為同一套 product data system 一起備份。Database recovery 必須保留 public registry、所有 tenant schema、Oban state、handoff、audit row 與 search table。Object recovery 必須保留這些 schema 引用的 attachment key。
Repository 沒有經過測試的 backup schedule、point-in-time recovery objective、cross-region plan 或 restore verification suite,也沒有公開 SLA、RPO 或 RTO。缺少 operator layer 時,目前 runtime 還不能作為 managed、production-ready infrastructure 銷售。