Migrating from supervisord
supervisord keeps your processes alive, and that’s about where it stops. The
web UI is an afterthought, the logs are flat files you tail by hand, and
finding out why something keeps restarting means SSHing in and reading
supervisord.log. RunWisp supervises the same processes and gives you per-run
history, streamed logs, and a notification when an instance flaps.
You don’t have to rewrite your config by hand. runwisp import supervisord
reads it — [include] files and all — and writes the runwisp.toml.
The one-liner
Section titled “The one-liner”Point it at your config, or pipe one in — both are first-class:
runwisp import supervisord /etc/supervisor/supervisord.conf -o runwisp.tomlcat /etc/supervisor/supervisord.conf | runwisp import supervisordrunwisp validateGiven a file, it follows any [include] directives relative to it, so a typical
conf.d/-style layout comes across in one shot. Each [program] becomes a
RunWisp service. Given:
[program:web]command=/usr/bin/gunicorn app:appdirectory=/srv/appuser=www-dataautostart=truestartsecs=10startretries=5stopsignal=INTenvironment=DJANGO_SETTINGS="prod",LOG_LEVEL=infostdout_logfile=/var/log/web.log
[program:worker]command=/srv/app/worker --idx %(process_num)snumprocs=4you get:
[services.web]run = "/usr/bin/gunicorn app:app"working_dir = "/srv/app"user = "www-data"healthy_after = "10s"start_retries = 5stop_signal = "SIGINT"
[services.web.env]DJANGO_SETTINGS = "prod"LOG_LEVEL = "info"
[services.worker]run = "/srv/app/worker --idx %(process_num)s"instances = 4Save it, runwisp validate, then runwisp daemon — your processes come up
under RunWisp, and you can watch them from the dashboard.
How the pieces map
Section titled “How the pieces map”A [program] is a long-running, auto-restarted process — which is exactly a
RunWisp service. Most keys carry straight over:
| supervisord | runwisp.toml | Notes |
|---|---|---|
[program:web] | [services.web] | One program → one service. |
command | run | %(program_name)s is expanded. |
directory | working_dir | |
user | user | Needs the daemon running as root to switch users. |
umask | umask | |
numprocs | instances | Each gets a RUNWISP_INSTANCE_INDEX (0-based). |
startsecs | healthy_after | Uptime that marks an instance healthy. |
startretries | start_retries | Fast failures tolerated before FATAL. |
stopsignal | stop_signal | INT → SIGINT. |
stopwaitsecs | graceful_stop | Grace window before SIGKILL. |
exitcodes | exit_codes | Which codes count as success. |
priority | priority | Boot start order. |
autostart | autostart | Whether instances start at boot. |
environment | [services.NAME.env] | Quoted values are parsed correctly. |
[group:site] programs=web,… | group = "site" on each | RunWisp has no program groups; members are tagged. |
[include] files=conf.d/*.conf | (followed and merged) | Resolved relative to the config file. |
What needs a human
Section titled “What needs a human”The importer flags everything it can’t map cleanly with a # TODO and a note
for well-known keys it recognises but can’t convert. Anything it doesn’t
recognise at all is skipped quietly — you won’t lose it, but you won’t
get a warning either. The ones to know about:
autorestart. RunWisp services are always-on — they restart whenever they exit.autorestart=true(and supervisord’s default,unexpected) map to a service directly.autorestart=falseis different: that’s a run-once process, so it’s imported as a task withrun_on_startandrestart = "never"instead of a service. If you relied onunexpectedto not restart on a clean exit, setexit_codesso RunWisp knows which codes are success.%(...)sexpansions.%(program_name)sis filled in. Anything else —%(process_num)s,%(ENV_x)s,%(host_node_name)s— is left in place with a TODO. Fornumprocs, the per-instance index isRUNWISP_INSTANCE_INDEXin the environment; swap it into your command.- Log files.
stdout_logfile/stderr_logfileare dropped — RunWisp captures both streams for every run automatically, no paths to manage. Tune size and retention withlog_max_sizeandkeep_runsinstead. - Daemon sections.
[supervisord],[supervisorctl],[unix_http_server],[inet_http_server], and[rpcinterface]are supervisord’s own plumbing and have no RunWisp equivalent — RunWisp’s daemon is configured in[daemon]and served over HTTP out of the box. They’re skipped. [eventlistener]/[fcgi-program]. Not supported — RunWisp has no event listener bus or FastCGI process manager. They’re skipped with a note so you know to handle them another way.
What you get that supervisord didn’t
Section titled “What you get that supervisord didn’t”- Logs you don’t have to
tail. Per-run stdout/stderr, streamed live to the Web UI and TUI and indexed for search — not a flat file you rotate by hand. - Restart visibility. Every restart is recorded with timing, so a flapping
instance is obvious instead of buried in
supervisord.log. Healthy uptime (healthy_after) resets the backoff; too many fast failures mark it FATAL. - Failure alerts. Notify on failure through Slack, Telegram, email, or a webhook.
- Start ordering.
prioritycontrols boot order, anddepends_ongates a service on another becoming healthy first — both honored at startup. - Trigger / stop from anywhere. Start and stop services from the dashboard,
TUI, or REST API; stops are graceful, honoring your
stop_signalandgraceful_stop.
Once it’s running and you’re happy, stop supervisord and let RunWisp own
supervision. runwisp.toml is now the single place your processes are defined.