Class: Heatwave::BoundedSubprocess
- Inherits:
-
Object
- Object
- Heatwave::BoundedSubprocess
- Defined in:
- app/lib/heatwave/bounded_subprocess.rb
Overview
Captures a subprocess under wall-clock, CPU, and address-space limits.
The stdout and stderr pipes drain concurrently so a noisy child cannot
deadlock while the parent waits. A timed-out child receives TERM, then
KILL if necessary, and is always reaped before the timeout propagates.
Defined Under Namespace
Classes: Error, MissingExecutable, TimeoutError
Constant Summary collapse
- DEFAULT_TIMEOUT =
Default wall-clock deadline in seconds.
10- DEFAULT_RLIMIT_CPU =
Default child CPU limit in seconds.
10- DEFAULT_RLIMIT_AS =
Default child address-space limit (1 GiB).
1 << 30
Class Method Summary collapse
-
.capture(*command, timeout: DEFAULT_TIMEOUT, rlimit_cpu: DEFAULT_RLIMIT_CPU, rlimit_as: DEFAULT_RLIMIT_AS) ⇒ Array(String, String, Process::Status)
Capture stdout, stderr, and exit status for an argv command.
Class Method Details
.capture(*command, timeout: DEFAULT_TIMEOUT, rlimit_cpu: DEFAULT_RLIMIT_CPU, rlimit_as: DEFAULT_RLIMIT_AS) ⇒ Array(String, String, Process::Status)
Capture stdout, stderr, and exit status for an argv command.
39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
# File 'app/lib/heatwave/bounded_subprocess.rb', line 39 def capture(*command, timeout: DEFAULT_TIMEOUT, rlimit_cpu: DEFAULT_RLIMIT_CPU, rlimit_as: DEFAULT_RLIMIT_AS) raise ArgumentError, 'command is required' if command.empty? limits = { rlimit_cpu:, rlimit_as: }.compact begin capture_with_limits(command, timeout:, limits:) rescue Errno::EINVAL # macOS rejects finite RLIMIT_AS at spawn time. Retry with the CPU # cap alone; a second EINVAL is unrelated and must propagate. raise unless limits.delete(:rlimit_as) retry end rescue Errno::ENOENT raise MissingExecutable, "#{command.first} binary not found" end |