Search the complete documentation

Try idempotency, proposal lifecycle, authentication, or ordering.

Navigate Open
繁體中文
Browse documentation

Relay · Operations

Deployment and operations

Relay ships an application runtime contract, not a managed service. The repository can build an Elixir release and a multi-stage container image. Your deployment owns image publication, PostgreSQL, R2, TLS termination, secrets, backups, rollout, rollback, and alerting.

Runtime dependencies

DependencyContract
PostgreSQL 18 or newerStores the public registry, per-tenant schemas, Oban jobs, handoffs, audit rows, and the default search index. Native uuidv7() is required.
Cloudflare R2-compatible storageStores message attachments. The production runtime currently requires R2 credentials when using the default storage client.
HTTP and WebSocket proxyMust preserve Phoenix WebSocket upgrades and forwarded HTTPS scheme.
OTLP collectorOptional operational dependency. The runtime defaults its trace exporter endpoint to http://localhost:4318.

Postgres FTS requires pg_trgm. zhparser is recommended for Chinese segmentation but optional. When unavailable, Relay falls back to simple_bigram, logs a warning, and marks affected search responses as degraded.

Required production configuration

VariablePurpose
DATABASE_URLPostgreSQL connection URL
SECRET_KEY_BASEPhoenix signing and encryption secret
CLOAK_KEYBase64-encoded 32-byte AES-GCM key for tenant secrets
PHX_SERVER=trueStarts the HTTP server in an Elixir release
ADMIN_TOKENProtects /api/admin/*; without it, admin API requests cannot authenticate
TONETIFY_RELAY_CORS_ORIGINSComma-separated browser origins; production fails closed for cross-origin requests when empty
R2_ENDPOINTR2 account endpoint
R2_BUCKETAttachment bucket
R2_ACCESS_KEY_IDBucket-scoped access key
R2_SECRET_ACCESS_KEYBucket-scoped secret

Common optional settings include PORT, PHX_HOST, POOL_SIZE, DNS_CLUSTER_QUERY, METRICS_TOKEN, OTEL_EXPORTER_OTLP_ENDPOINT, TONETIFY_RELAY_WEBHOOK_URL, TONETIFY_RELAY_WEBHOOK_SECRET, upload and download URL TTLs, and SEARCH_CHINESE_MODE.

Set METRICS_TOKEN in every exposed production environment. When it is unset, /metrics is reachable without application-layer authentication. Network policy should restrict the endpoint even when a token is present.

Do not log ADMIN_TOKEN, CLOAK_KEY, R2 credentials, host webhook secrets, host-sync Basic credentials, tenant JWT secrets, or presigned attachment URLs.

Build and start

The repository includes server/Dockerfile, which builds the Mix release and starts bin/chataas. A non-container deployment can run the same release directly:

PHX_SERVER=true bin/chataas start

The repository does not currently publish a versioned image, provide a supported Compose stack, or define a platform-neutral deployment manifest. Treat the Dockerfile as a build input, not a distributed product artifact.

Migrations

Run migrations before sending traffic to a new release:

bin/chataas eval "Chataas.Release.migrate()"

This entrypoint applies public-schema migrations, discovers every tenant_% schema, and applies tenant migrations to each one. Migration traffic should use a direct PostgreSQL connection or a pool mode known to support DDL and advisory behavior.

Use forward-compatible expand and contract changes when old and new application versions can overlap. The runtime includes a public-schema rollback function, but there is no complete automated rollback contract for both public and tenant schemas. Restore rehearsals and downgrade compatibility remain operator responsibilities.

Health and deploy gates

EndpointMeaning
GET /livezProcess liveness without dependency checks
GET /healthLegacy alias for liveness
GET /ready or GET /readyzExecutes SELECT 1 against the primary database and returns 503 when unavailable

A minimum deployment gate is:

curl -fsS "$BASE_URL/health"
curl -fsS "$BASE_URL/ready"
curl -fsS "$BASE_URL/api/channels" \
  -H "Authorization: Bearer $TENANT_USER_JWT"

Then connect a real WebSocket client, join tonetify-relay:<tenant_id>:<channel_id>, send msg:send with a unique nonce, and confirm the acknowledgement contains id and seq. Liveness and readiness alone do not prove tenant migration, authentication, fan-out, or message delivery.

Workers and durable handoffs

Relay runs Oban queues for WebSocket fan-out, host webhooks, adapter egress, user exports, governance cleanup, R2 deletion, and search reindexing. Message-side effects are first written to public.post_commit_handoffs, then drained by sink workers.

The periodic poller provides correctness after a best-effort immediate wakeup. Stale processing claims are recovered after a default five-minute threshold. dispatch_seq orders handoff claims; message order still comes from channel-local messages.seq.

Operators should watch queue availability, retry exhaustion, oldest pending handoff age, per-sink backlog, webhook dead letters, R2 deletion failures, reindex status, and database pool saturation. A healthy HTTP process can still have a growing delivery backlog.

Metrics and traces

GET /metrics exposes Phoenix, Ecto, VM, business-event, search, R2, and post-commit handoff series. Useful signals include:

  • successful send, edit, retract, and delete throughput;
  • join and catch-up activity;
  • WebSocket and HTTP error buckets;
  • handoff transition counts and backlog gauges;
  • search, webhook, and object-deletion failures.

Typing is best-effort and intentionally absent from durable delivery and business metrics. A reconnect metric means a successful join carrying last_seq, not every lower-level socket reconnect.

Relay emits OpenTelemetry traces through OTLP. The repository does not provide dashboards, alert thresholds, paging policy, or service objectives as a supported product package.

Backup and recovery boundary

Back up PostgreSQL and the attachment bucket as one product data system. Database recovery must preserve the public registry, every tenant schema, Oban state, handoffs, audit rows, and search tables. Object recovery must preserve attachment keys referenced by those schemas.

The repository does not include a tested backup schedule, point-in-time recovery objective, cross-region plan, or restore verification suite. It also does not publish an SLA, RPO, or RTO. These gaps prevent the current runtime from being sold as managed, production-ready infrastructure without an operator layer.

Related: Data lifecycle and audit · Limits and errors · Relay overview