Skip to main content

Restart Policies

Runix supports three restart policies that control automatic process restart after exit.

Policies​

PolicyOn Exit Code 0On Exit Code ≠ 0Use Case
alwaysRestartRestartLong-running services that should never be down
on-failureNo restartRestartWorkers that should restart on crash but not on clean exit
neverNo restartNo restartOne-shot tasks, batch jobs

Configuration​

processes:
api:
entrypoint: ./cmd/api
restart_policy: always
max_restarts: 10

worker:
entrypoint: worker.py
restart_policy: on-failure
max_restarts: 5

migrate:
entrypoint: migrate.sh
restart_policy: never

Exponential Backoff​

When a restart is triggered, Runix waits using exponential backoff to avoid rapid restart loops.

Backoff Formula​

delay = min(backoff_base * 2^attempt, backoff_max)

Configuration​

FieldDefaultDescription
backoff_base1sInitial delay after first crash
backoff_max60sMaximum delay cap

Example Progression​

With defaults (base: 1s, max: 60s):

Restart #Delay
11s
22s
34s
48s
516s
632s
760s (capped)
860s (capped)

Implementation​

The backoff calculator is in internal/supervisor/backoff.go:

type Backoff struct {
Base time.Duration
Max time.Duration
attempt int
}

func (b *Backoff) Next() time.Duration {
delay := b.Base * time.Duration(1<<uint(b.attempt))
b.attempt++
if delay > b.Max {
return b.Max
}
return delay
}

func (b *Backoff) Reset() {
b.attempt = 0
}

The backoff is reset to 0 when the process stays running for a sustained period (indicating stable operation).

Max Restarts​

The max_restarts field caps the total number of automatic restarts:

ValueBehavior
0Unlimited restarts
N > 0Stop restarting after N attempts

When max_restarts is reached:

  • The process stays in crashed state
  • No more automatic restarts
  • Manual runix restart api still works
  • The restart counter resets on manual restart

Interaction with Health Checks​

When health checks are configured:

  1. Process starts → health checker begins polling
  2. Health check fails N consecutive times (default 3) → process marked unhealthy
  3. onUnhealthy callback triggers a restart
  4. Restart uses the same backoff and max_restarts limits

What's Next​