Skip to main content

Hooks

Runix supports 10 lifecycle hook points that execute shell commands at specific stages of a process's lifecycle.

Hook Points​

HookWhenBlocks Process?Failure Behavior
pre_startBefore process startsYes — prevents startProcess enters errored state
post_startAfter process startsNo (async)Logged as warning
pre_stopBefore process stopsNo (best-effort)Logged as warning
post_stopAfter process stopsNo (async)Logged as warning
pre_restartBefore process restartsNoLogged as warning
post_restartAfter process restartsNo (async)Logged as warning
pre_reloadBefore graceful reloadNoLogged as warning
post_reloadAfter graceful reloadNo (async)Logged as warning
pre_healthcheckBefore health check runsNoLogged as warning
post_healthcheckAfter health check completesNo (async)Logged as warning

Configuration​

processes:
api:
entrypoint: ./cmd/api
hooks:
pre_start:
command: "echo 'Starting API at $(date)' >> /var/log/runix-events.log"
timeout: 10s
post_start:
command: "curl -X POST http://localhost:8080/warm-cache"
timeout: 30s
pre_stop:
command: "curl -X POST http://localhost:8080/drain-connections"
timeout: 15s
post_stop:
command: "echo 'API stopped' >> /var/log/runix-events.log"
pre_reload:
command: "echo 'Reloading API' >> /var/log/runix-events.log"
timeout: 10s

Hook Configuration​

Each hook has two fields:

FieldTypeDefaultDescription
commandstring(none)Shell command to execute (sh -c)
timeoutduration30sMaximum execution time

If command is empty or not set, the hook is skipped.

Execution​

All hooks are executed via sh -c <command>:

cmd := exec.CommandContext(ctx, "sh", "-c", hook.Command)

This means hooks have full shell capabilities — pipes, redirects, environment variables, etc.

Environment​

Hooks inherit the process's environment variables plus any overlay from the process config.

Timeout​

If a hook exceeds its timeout, the context is cancelled and the process is killed. The hook's stdout/stderr are captured and logged.

Blocking vs Non-Blocking​

Only pre_start is a true blocking hook — if it fails, the process does not start. All other hooks are non-blocking: failures are logged but do not prevent the lifecycle action.

Hook Chain​

Multiple hooks can be defined. They execute in this order during each lifecycle event:

Start: pre_start → start process → post_start Stop: pre_stop → stop process → post_stop Restart: pre_restart → stop → start → post_restart Reload: pre_reload → reload process → post_reload Health check: pre_healthcheck → run check → post_healthcheck

Examples​

Database Migration Before Start​

hooks:
pre_start:
command: "goose -dir migrations postgres $DATABASE_URL up"
timeout: 60s

Cache Warming After Start​

hooks:
post_start:
command: "sleep 2 && curl -s http://localhost:8080/preload"
timeout: 30s

Graceful Drain Before Stop​

hooks:
pre_stop:
command: "curl -X PUT http://localhost:8080/health/unhealthy && sleep 5"
timeout: 15s

Health Check Notification​

hooks:
post_healthcheck:
command: 'curl -X POST https://hooks.slack.com/services/XXX -d ''{"text": "Health check completed for process"}'''
timeout: 10s

What's Next​