Deploying Wurk
Wurk is a drop-in for Sidekiq, so it deploys the same way: a long-running worker
process supervised by your init system, signalled for quiet/reload/stop during a
deploy. If you already run Sidekiq under systemd or capistrano-sidekiq, the only
change is the binary name (sidekiq → wurk) — the signals, flags, and config
file are identical.
Authoritative signal reference:
docs/target/sidekiq-free.md§21 (CLI). Just getting a worker running (incl. standalone, no Rails)? Seedocs/running.md. Migrating an existing app? Start withdocs/migrate-from-sidekiq.md.
The runner
| Binary | What it does | Sidekiq equivalent |
|---|---|---|
bundle exec wurk |
Single worker process, thread pool | sidekiq |
bundle exec wurkswarm |
Forks N worker children from one preloaded parent (real parallelism) | sidekiqswarm |
sidekiqswarm ships as an alias for wurkswarm, so an existing Enterprise
sidekiqswarm invocation keeps working unchanged.
In a Rails app the engine auto-starts the swarm during boot, so your web/worker
dynos often need no separate worker command at all — set WURK_DISABLED=1 on
processes that should not fork workers (e.g. the web process). The standalone
runners below are for non-Rails apps, or when you want the worker in its own unit.
Common flags (same as Sidekiq): -c concurrency, -q queue[,weight], -r require
path, -t shutdown timeout (seconds), -e environment, -C config YAML. With no
-C, Wurk auto-discovers config/wurk.yml then config/sidekiq.yml (.erb ok).
Signals
These are what your deploy tooling sends. Wurk implements the full Sidekiq set.
| Signal | Effect |
|---|---|
TERM / INT |
Graceful shutdown — stop fetching, let in-flight jobs finish up to the shutdown timeout (-t, default 25s), then exit. |
TSTP |
Quiet — stop fetching new work; in-flight jobs finish. Standalone has no resume (quiet, then stop); under wurkswarm, CONT resumes. |
USR1 |
wurkswarm only — zero-downtime rolling restart: fork a replacement child, wait for its heartbeat, then TERM the old one, slot by slot. |
TTIN / INFO |
Dump every thread's backtrace to the log (for diagnosing a stuck worker). |
USR2 |
Reopen log files (logrotate) on swarm children. |
The standard deploy dance is quiet, then stop: send TSTP early in the deploy so
the old worker stops claiming new jobs, then TERM once the new release is live. A
SIGKILL at any point is safe — reliable fetch keeps in-flight jobs on a per-process
private list in Redis, and they're reclaimed on the next boot.
systemd
A ready-to-edit unit ships at examples/wurk.service.
Copy it, adjust the paths/user, and install:
sudo cp examples/wurk.service /etc/systemd/system/wurk.service
sudo systemctl daemon-reload
sudo systemctl enable --now wurk
Then:
sudo systemctl reload wurk # SIGTSTP — quiet (stop fetching, finish in-flight)
sudo systemctl stop wurk # SIGTERM — graceful drain up to the shutdown timeout
sudo systemctl restart wurk # quiet+stop+start
journalctl -u wurk -f # tail logs
Two details that differ from a stock Sidekiq unit:
Type=simple, notType=notify. Wurk does not emitsd_notifyreadiness or watchdog pings, so there's noWatchdogSec. systemd considers the process ready as soon asExecStartforks.TimeoutStopSec≥ shutdown timeout. The unit setsTimeoutStopSec=30against the default 25s drain so a clean shutdown always wins before systemd'sSIGKILL. If you raise-t, raiseTimeoutStopSecto match.
Multiple workers
Run several workers on one host with a template unit. Save the example as
/etc/systemd/system/wurk@.service and start instances:
sudo systemctl enable --now wurk@1 wurk@2 wurk@3
Or run one wurkswarm unit instead, which forks children itself — change
ExecStart to bundle exec wurkswarm -e production and
ExecReload=/bin/kill -USR1 $MAINPID (rolling restart instead of plain quiet).
capistrano-sidekiq
capistrano-sidekiq shells out to
the runner and sends the signals above for quiet/restart/stop. The signal handling is
fully drop-in:
Sidekiq::CLIis aliased toWurk::CLI, and- the
TSTP/TERM/USR1signal semantics match exactly.
The one thing to map is the binary name. Wurk ships wurk, wurkswarm, and a
sidekiqswarm alias — but there is no sidekiq binary (see
docs/migrate-from-sidekiq.md). So an Enterprise
sidekiqswarm invocation drops in unchanged, while a bundle exec sidekiq invocation
needs pointing at wurk: set sidekiq_role/sidekiq_command config to
wurk/wurkswarm, or add a tiny bin/sidekiq shim that execs wurk. The systemd
integration mode drops in the same way — replace the generated unit's ExecStart with
bundle exec wurk and keep the rest.
Heroku / Procfile
worker: bundle exec wurkswarm -e production
Use wurkswarm for fork-based parallelism inside the dyno (set WURK_COUNT to the
dyno's core count), or bundle exec wurk for a single process if you'd rather scale
out by adding worker dynos. Heroku sends SIGTERM on dyno cycle, which triggers
Wurk's graceful drain — set the shutdown timeout (-t) below Heroku's 30s kill window
so jobs finish cleanly.