The backend container includes a healthcheck that monitors the /health endpoint. The healthcheck:
- Probes every 30 seconds
- Waits up to 3 seconds for a response
- Allows 5 seconds after startup before considering the container unhealthy
- Marks the container unhealthy after 3 consecutive failed checks
A healthy container returns {"status": "ok"} from GET /health. Any other status or timeout marks
the container as unhealthy.
Choose a restart policy appropriate for your deployment platform:
services:
backend:
build: .
restart_policy:
condition: on-failure
max_retries: 3
delay: 5sThis restarts the container on non-zero exit or unhealthy status, with a 5-second delay between attempts and a max of 3 retries.
spec:
containers:
- name: backend
image: trivela-backend:latest
livenessProbe:
httpGet:
path: /health
port: 3001
initialDelaySeconds: 10
periodSeconds: 30
timeoutSeconds: 3
failureThreshold: 3
restartPolicy: AlwaysThis uses the built-in healthcheck via liveness probe and restarts the pod on failure.
version: '3.8'
services:
backend:
image: trivela-backend:latest
deploy:
restart_policy:
condition: on-failure
delay: 5s
max_attempts: 3Similar to Docker Compose, restarts on failure with exponential backoff.
Blue/green deployment eliminates downtime by running two identical backend environments in parallel and atomically switching traffic only after the new environment is verified healthy.
| Colour | Role |
|---|---|
| blue | Currently serving production traffic |
| green | New version under validation |
The load balancer (nginx) maintains an upstream trivela_backend block that points to whichever
colour is active. Switching traffic is a single nginx reload — no DNS changes, no downtime.
Both environments are identical in configuration. They differ only in port:
| Environment | Internal Port |
|---|---|
| blue | 3001 |
| green | 3002 |
- Build the new image and tag it
trivela-backend:green. - Start green alongside blue:
docker compose --profile green up -d backend-green
- Poll
/healthon the green container (max 60 s):./scripts/deploy-blue-green.sh
- The script updates the nginx upstream to point at green and reloads nginx.
- After 30 s the script checks green logs for errors. If none are found it stops the blue container.
- On any failure the script rolls back by switching nginx back to blue and stopping green.
The nginx config uses an upstream block so the active backend can be changed with a single
variable substitution and reload:
upstream trivela_backend {
server ${TRIVELA_BACKEND_HOST}:${TRIVELA_BACKEND_PORT};
}At switch time deploy-blue-green.sh writes the correct host/port into nginx/trivela.conf and
runs nginx -s reload.
If the green environment fails health checks or log scanning finds errors:
- nginx upstream is reverted to blue.
- nginx is reloaded.
- The green container is stopped.
- The operator is notified via the script exit code (non-zero).
See RUNBOOK.md for full rollback procedures.
Both the rewards and campaign contracts use a propose-then-accept admin rotation pattern to
eliminate the "keyed-in wrong address, key is now lost" failure mode of a one-step set_admin call.
admin() -> Address— the current admin.pending_admin() -> Option<Address>— the admin proposed but not yet accepted.Nonewhen no transfer is in flight.
- Current admin calls
propose_admin(current_admin, new_admin). The admin slot is not updated yet; the address goes intopending_admin. The current admin can callpropose_adminagain with a different address to amend the proposal, or callcancel_admin_transferto drop it entirely. - New admin calls
accept_admin(new_admin)from their own wallet. The call'srequire_authproves the new admin actually controls the key. On success the admin slot is updated andpending_adminis cleared.
Until step 2 happens the existing admin retains full control, so a typo in step 1 cannot brick the contract.
- Generate the new admin keypair on the target signer (hardware wallet, multisig, etc.). Do not copy the secret over the wire.
- Test the new keypair can sign a no-op transaction on the same network.
- Call
propose_adminfrom the current admin and confirm theaproposedevent fires with the expectednew_adminaddress. - Call
accept_adminfrom the new admin keypair within 30 days (the instance-storage TTL). - Verify
admin()returns the new address andpending_admin()returnsNone.