2.6 KiB
| name | description |
|---|---|
| async-task-hygiene | Habits for background tasks and waiting. Don't truncate a background task's captured output with a tail/head pipe - the full output is saved regardless, so piping it away only throws away what you might need, slice it after the fact instead. Don't assume a background task from before a restart is still exactly where you left it - check its status rather than blindly re-running it. Prefer ending your turn (or a short bounded wait) over a sleep-based polling loop when waiting on something in progress. Use this whenever you launch, check on, or wait for background work. |
Async Task Hygiene
Background tasks (a build, a long command, anything you fire off and check on later) have a few sharp edges worth knowing.
Don't pipe away captured output
Don't do some-long-command | tail -N (or | head -N) when launching
a background task. The runner captures the full stdout/stderr to a
file regardless of what you piped through - so truncating the live
output doesn't save anything, it just means you can't slice the part
you didn't think you'd need until you needed it. Run the full command,
then read/grep the captured file however you want afterward. (Genuinely
unbounded streams you'll never read in full are the rare exception to
this - not normal command output.)
Don't blindly re-run a task after a restart
If your environment restarted (container rebuild, harness restart) and you had background tasks in flight, don't assume they're gone and re-launch them from scratch. Check their status first - a task may still be running, may have finished while you were down, or may genuinely need restarting. Re-running blind can duplicate work or step on a task that's still making progress.
Prefer ending the turn over a sleep-loop
When you're waiting on something (a build, a task you started, a fixed
delay before retrying), a sleep-then-check loop blocks you from
reacting to anything else for that whole window. Prefer:
- Between units of work: just end the turn. Whatever wakes you next (the task's own completion, a new message) drives the follow-up - there's nothing to poll for.
- Within a turn, if you must wait: a short bounded wait that can be interrupted by new input beats a blind sleep, since it lets you react immediately if something more urgent shows up instead of only after your poll interval elapses.
Concretely: if you started something and plan to check back, don't
sleep N && check-status in a loop. Either end the turn and let the
task's own completion (or the next message) drive the next step, or use
an interruptible wait if you genuinely need to stay in-turn.