perf: shellcheck concurrency limiter, debounce, and orphan reaper#3136
perf: shellcheck concurrency limiter, debounce, and orphan reaper#3136marcusquinn merged 1 commit intomainfrom
Conversation
The wrapper now limits concurrent shellcheck processes to 4 (configurable via SHELLCHECK_MAX_PARALLEL), debounces repeated checks on unchanged files within 10s (SHELLCHECK_DEBOUNCE_SEC), and uses fast-path .real binary lookup instead of expensive PATH scanning (3.4s -> 0.38s per invocation). The process guard now kills orphaned shellcheck processes (ppid=1, age >120s) whose parent language server exited — these accumulate indefinitely and waste CPU competing with each other. Measured improvement: - Cold run: 3.4s -> 0.38s (9x faster) - Debounced: 3.4s -> 0.18s (19x faster) - 8 concurrent: 27s -> 1.5s (18x faster) - Orphan cleanup: 120 -> 2 processes on first run
|
Warning You have reached your daily quota limit. Please wait up to 24 hours and I will start processing your requests again! |
|
Caution Review failedPull request was closed or merged during review WalkthroughTwo shell scripts are enhanced to control unbounded ShellCheck process spawning: the process-guard helper now tracks parent process IDs to detect orphans, and the ShellCheck wrapper introduces concurrency limiting via slot-based locking and file-change debouncing to prevent excessive concurrent invocations. Changes
Sequence Diagram(s)sequenceDiagram
participant Client as Client/Caller
participant Wrapper as ShellCheck Wrapper
participant Cache as Debounce Cache
participant LockMgr as Slot Lock Manager
participant Real as Real ShellCheck Binary
Client->>Wrapper: shellcheck [args]
Wrapper->>Wrapper: Extract target file & args
Wrapper->>Cache: Check if file unchanged<br/>within debounce window?
alt Debounce Hit
Cache-->>Wrapper: Hit (cached, skip)
Wrapper->>Client: Return cached result
else Debounce Miss
Cache-->>Wrapper: Miss/Expired
Wrapper->>LockMgr: Acquire concurrency slot<br/>(up to 3 retries)
LockMgr->>LockMgr: Cleanup stale locks
LockMgr-->>Wrapper: Slot acquired (slot ID)
Wrapper->>Real: Execute real ShellCheck
Real-->>Wrapper: Output & exit code
Wrapper->>Cache: Update cache with<br/>file mtime
Wrapper->>LockMgr: Release slot
LockMgr-->>Wrapper: Slot released
Wrapper->>Client: Return ShellCheck output
end
Estimated Code Review Effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly Related PRs
Suggested Labels
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches
🧪 Generate unit tests (beta)
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. Comment |
🔍 Code Quality Report�[0;35m[MONITOR]�[0m Code Review Monitoring Report �[0;34m[INFO]�[0m Latest Quality Status: �[0;34m[INFO]�[0m Recent monitoring activity: 📈 Current Quality Metrics
Generated on: Sat Mar 7 17:45:14 UTC 2026 Generated by AI DevOps Framework Code Review Monitoring |
|



Summary
Follows up on #3125 (binary wrapper fix). The wrapper prevented memory explosions but didn't address the volume problem: language servers spawn shellcheck on every
.shfile edit, and with multiple concurrent workers, this creates 100+ competing processes that waste CPU and never get cleaned up.Changes
shellcheck-wrapper.sh— three new resource controlsFast-path binary lookup: Check
.realsibling and common.reallocations BEFORE PATH scanning. Eliminates 3s startup overhead from recursive wrapper resolution (3.4s → 0.38s per invocation).Concurrency limiter: mkdir-based semaphore limits concurrent shellcheck processes to 4 (configurable via
SHELLCHECK_MAX_PARALLEL). Excess invocations wait 3s then exit silently — no diagnostics is better than 100 competing processes. Stale locks auto-cleaned by checking if holder PID is alive.Debounce cache: Skips re-checking files that haven't been modified within 10s (configurable via
SHELLCHECK_DEBOUNCE_SEC). Uses file mtime + cksum-based cache key in/tmp/shellcheck-wrapper-cache/.Note: Changed
execto regular call so thetrap EXITcan release the concurrency slot. Trade-off is one extra bash process per invocation, but with max 4 concurrent, that's negligible.process-guard-helper.sh— orphan reaperAdded orphan detection to
cmd_kill_runawaysandcmd_scan: shellcheck processes with ppid=1 (parent died, reparented to init) and age >120s are killed. These are language-server-spawned checks whose parent OpenCode process exited — nobody is reading the output, so the work is wasted CPU.Also added
ppidcolumn to scan output and status JSON for visibility.Measured results
Closes #2915
Summary by CodeRabbit
Bug Fixes
Chores