Skip to content

[defaults]

[defaults] is the one section in runwisp.toml that doesn’t define something to run. It defines fallback values that every [tasks.*] and [services.*] inherits unless they override the field themselves.

It exists because writing the same keep_for = "30d" and log_max_size = "100mb" on twenty tasks gets tedious. Pull those into [defaults] once, override per-task only when the value is different.

[defaults]
timeout = "1h"
log_max_size = "100mb"
log_on_full = "drop_old"
keep_runs = 50
keep_for = "30d"
backoff_reset_after = "60s"
KeyDefaultWhat it does
timeout(unset)Default per-attempt wall-clock cap. Unset means no timeout. Tasks only — services don’t have a per-attempt timeout.
log_max_size100MBDefault per-run log cap. Units b/kb/mb/gb/tb. Bare 0 and negatives are rejected.
log_on_full"drop_old"Default overflow policy: drop_new, drop_old, kill_task.
keep_runs(unset)Default row-count retention. Positive integer; hard internal cap of 1 000 000. Bare 0 and negatives are rejected.
keep_for(unset)Default age-based retention. Accepts d/w/h/m units. Zero / negative durations are rejected.
backoff_reset_after"60s"A service instance that stays up at least this long resets its restart counter. Services only. Per-service override supported.

There is no default cron, no default on_overlap, no default retry_*, no default max_concurrent, no default queue_max, no default graceful_stop. Those vary per task by intent; defaulting them would hide behaviour. Per-task graceful_stop falls back to its built-in default when omitted; set it on each table that needs a different window.

The daemon-wide [daemon] shutdown_timeout is a separate top-level setting — it bounds the whole-daemon shutdown phase. Each task/service still gets its own graceful_stop window inside that cap. If a graceful_stop exceeds [daemon] shutdown_timeout the daemon emits a boot-time warning naming the task.

For each task or service:

  1. If the field is set on the [tasks.*] / [services.*] table, use that.
  2. Else if it’s set in [defaults], use that.
  3. Else fall back to the built-in default (e.g. 100MB for log_max_size).

Omitting a numeric retention field at every level means no cap — runs accumulate until you set a value somewhere. Bare 0, negative values, and out-of-range strings are rejected at config load, so “forgot to cap” never silently means “deleted everything.”

[defaults]
timeout = "30m" # most tasks should die after 30 minutes
log_max_size = "50mb" # smaller default, override for noisy tasks
keep_runs = 100
keep_for = "30d"
backoff_reset_after = "30s" # services that stabilise in 30s reset
[tasks.heartbeat]
cron = "*/5 * * * *"
run = "/usr/local/bin/heartbeat"
# inherits 30m timeout, 50mb log cap, 100 runs, 30d retention
[tasks.nightly-export]
cron = "0 2 * * *"
timeout = "4h" # overrides default — exports take longer
log_max_size = "500mb" # overrides default — output is large
graceful_stop = "20s" # this one needs more than the built-in 5s
run = "/usr/local/bin/export"
[services.flaky-worker]
backoff_reset_after = "2m" # overrides default — this one takes longer to stabilise
run = "/usr/local/bin/worker"
  • It doesn’t apply to [storage] — that’s a global cap, not a per-task default.
  • It doesn’t apply to [notify] settings (coalesce_window, queue_size, etc.).
  • It doesn’t apply to [daemon] shutdown_timeout — that’s a daemon-wide setting, not a per-task value to inherit.
  • Notification routing (notify_on_failure, notify_on_success) has no defaulting layer — you set it per task.