Tuning tman for RSpec
Chatty during the run; preloaders like Spring leave daemons behind.
Recommended starting caps
| cap | start at | what it answers |
|---|---|---|
stall | 10m | hang backstop — no output and no CPU/IO activity for this long |
max-time | 20m | wall-clock budget — the only cap that bounds a run that is working but will never finish |
max-mem | 4096 | RSS ceiling across the process tree |
max-parallel | 1 | slots per name-and-directory bucket |
These are starting points derived from how RSpec behaves, not measurements of your machine. Every one of them should be replaced by a number you took from your own runs — the last section on this page is how.
alias "test" {
command "bundle"
args "exec" "rspec"
max-time "20m"
max-mem 4096
max-parallel 1
}RSpec prints a character per example, so the run itself is never quiet. The quiet part is in front of it: booting a Rails application, which on a large app means loading the whole framework, the gem set, and the schema before the first dot appears.
Disable preloaders under supervision
Spring and its relatives work by keeping a resident daemon that survives your command. That is directly at odds with supervision: the work you want capped happens in a process outside the tree tman is watching, so caps do not apply to it — and the daemon is exactly the kind of long-lived leftover the reaper exists to clean up.
alias "test" {
command "bundle"
args "exec" "rspec"
max-time "20m"
max-parallel 1
}
// and in the project, so the alias means what it says:
// DISABLE_SPRING=1 (or remove spring from the test group)One slot, because of the database
A Rails test suite owns its test database. Two concurrent runs in the same checkout truncate each other's tables mid-example, and the resulting failures look like flakes rather than like a collision. max-parallel 1 is the honest setting unless you have per-process database isolation configured, in which case raise it deliberately.
Turn the starting point into a real number
Everything above is derived from how this tool behaves, not from your machine. The numbers that matter come from your own runs, and getting them takes one command:
tman status --json | jq '.runs[] | {name, exit, duration_ms}'Set max-time from the slowest successful run you are willing to wait for, with real headroom — a cap that fires on healthy work teaches everyone to raise the cap, and after a few rounds of that it bounds nothing. Set stall from the longest stretch the command legitimately produces no output and no CPU, then double it.
Exit 124, 125, and 126 are findings, not flakes. 124 is a wall-clock timeout, 125 a stall, 126 a resource cull. Widening the cap that fired is the right response only after you know why it fired — the first two times a suite trips
max-mem, the interesting question is what is holding the memory.
Frequently asked
Why does tman recommend disabling Spring for RSpec?
Spring keeps a resident daemon that outlives your command, so the work you meant to cap runs in a process outside the supervised tree and the caps do not apply to it. The daemon is also precisely the kind of leftover the orphan reaper is for. Disable it in the supervised alias and the caps mean what they say.