Skip to content

Enforce --timeout when a command leaves a child running - #218

Merged
vertti merged 2 commits into
mainfrom
fix-command-timeout
Aug 11, 2026
Merged

Enforce --timeout when a command leaves a child running#218
vertti merged 2 commits into
mainfrom
fix-command-timeout

Conversation

@vertti

@vertti vertti commented Aug 11, 2026

Copy link
Copy Markdown
Owner

--timeout was unenforceable against any version command that leaves a background child holding stdout. Measured with a script that backgrounds a sleep before exiting:

$ cat slowchild
#!/bin/sh
sleep 30 &
echo "v1.0.0"

$ time preflight cmd ./slowchild --timeout 2s
elapsed: 31s          # timeout was 2s

Why

Stdout/Stderr are bytes.Buffer, not *os.File, so os/exec creates pipes and a copying goroutine, and Wait blocks until the pipe reaches EOF. CommandContext kills only the direct child — a grandchild holding the write end keeps the pipe open, so the deadline never takes effect.

In a container entrypoint this is worse than a failed check: a failure is reported and the container stops; a hang just sits there. Realistic triggers are version commands that daemonize — a service wrapper, a monitoring agent, a docker shim.

Fix

cmd.WaitDelay = time.Second, which bounds how long Wait blocks after cancellation. Two lines including the constant.

before:  31s elapsed for a 2s timeout
after:    1s elapsed  (200ms deadline + 1s WaitDelay in the test; 2s + 1s via the CLI)

Tests

runner_unix_test.go, written first and confirmed red — it hit the 15s bound and reported "the 200ms timeout was not enforced", then passed in 1.11s after the fix.

Two cases:

  • the grandchild-holds-the-pipe scenario, asserted via a generous 15s bound against a 60s child so it isn't timing-fragile
  • a normal command still returns its output, so WaitDelay doesn't truncate healthy runs

Unix-tagged, since it needs a shell script. It's self-contained — no shared helpers cross the build tag, which is the mistake #213 fixed in resourcecheck.

Note

TestTCPCommand fails on this branch. That's the 127.0.0.1:1 flake fixed in #217, which isn't merged yet — unrelated to this change, and this branch only touches pkg/cmdcheck.

Stdout and Stderr are buffers rather than files, so os/exec pipes them and
Wait blocks until the pipe reaches EOF. CommandContext kills only the direct
child, so a grandchild holding the write end keeps the pipe open and the
deadline never applies.

A version command that daemonizes — a service wrapper, an agent, a docker
shim — therefore hung the check indefinitely. Measured with a script that
backgrounds a sleep before exiting:

    preflight cmd ./slowchild --timeout 2s     31s elapsed

In a container entrypoint that is a permanent stall rather than a failed
check, which is the worse outcome: a failure is reported, a hang is not.

Setting cmd.WaitDelay bounds Wait after cancellation. Same command now
returns in 1s, and commands that exit normally are unaffected.
@coderabbitai

coderabbitai Bot commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

@vertti, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 48 minutes

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 84c7413e-999f-44f3-a3aa-e5b0c6cbb17f

📥 Commits

Reviewing files that changed from the base of the PR and between 6455c72 and 0ccbf5a.

📒 Files selected for processing (2)
  • pkg/cmdcheck/runner.go
  • pkg/cmdcheck/runner_unix_test.go

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@codecov

codecov Bot commented Aug 11, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 93.11%. Comparing base (6455c72) to head (0ccbf5a).

Additional details and impacted files
@@           Coverage Diff           @@
##             main     #218   +/-   ##
=======================================
  Coverage   93.10%   93.11%           
=======================================
  Files          49       49           
  Lines        1872     1873    +1     
=======================================
+ Hits         1743     1744    +1     
  Misses         93       93           
  Partials       36       36           
Files with missing lines Coverage Δ
pkg/cmdcheck/runner.go 100.00% <100.00%> (ø)
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@vertti
vertti merged commit 9b003da into main Aug 11, 2026
19 checks passed
@vertti
vertti deleted the fix-command-timeout branch August 11, 2026 13:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant