Skip to content

Commit

Permalink
[core] Merge pull request rspec/rspec-core#2739 from rspec/detach-pro…
Browse files Browse the repository at this point in the history
…cess-to-avoid-zombie

Detach bisect subprocesses to avoid making zombie processes

---
This commit was imported from rspec/rspec-core@efbac94.
  • Loading branch information
JonRowe committed Sep 30, 2020
1 parent 8b37b66 commit eb4a550
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 3 deletions.
2 changes: 2 additions & 0 deletions rspec-core/Changelog.md
Expand Up @@ -6,6 +6,8 @@ Bug Fixes:
* Ensure custom error codes are returned from bisect runs. (Jon Rowe, #2732)
* Ensure `RSpec::Core::Configuration` predicate config methods return booleans.
(Marc-André Lafortune, #2736)
* Prevent `rspec --bisect` from generating zombie processes while executing
bisect runs. (Benoit Tigeot, Jon Rowe, #2739)

### 3.9.2 / 2020-05-02
[Full Changelog](http://github.com/rspec/rspec-core/compare/v3.9.1...v3.9.2)
Expand Down
7 changes: 5 additions & 2 deletions rspec-core/lib/rspec/core/bisect/fork_runner.rb
Expand Up @@ -91,9 +91,12 @@ def initialize(runner, channel)
end

def dispatch_specs(run_descriptor)
fork { run_specs(run_descriptor) }
pid = fork { run_specs(run_descriptor) }
# We don't use Process.waitpid here as it was causing bisects to
# block due to the file descriptor limit on OSX / Linux.
# block due to the file descriptor limit on OSX / Linux. We need
# to detach the process to avoid having zombie processes
# consuming slots in the kernel process table during bisect runs.
Process.detach(pid)
end

private
Expand Down
46 changes: 45 additions & 1 deletion rspec-core/spec/integration/bisect_spec.rb
Expand Up @@ -33,14 +33,58 @@ def bisect(cli_args, expected_status=nil)
end
end

context "when the bisect commasaturingnd is long" do
context "when the bisect command saturates the pipe" do
# On OSX and Linux a file descriptor limit meant that the bisect process got stuck at a certain limit.
# This test demonstrates that we can run large bisects above this limit (found to be at time of commit).
# See: https://github.com/rspec/rspec-core/pull/2669
it 'does not hit pipe size limit and does not get stuck' do
output = bisect(%W[spec/rspec/core/resources/blocking_pipe_bisect_spec.rb_], 1)
expect(output).to include("No failures found.")
end

it 'does not leave zombie processes', :unless => RSpec::Support::OS.windows? do
bisect(['--format', 'json', 'spec/rspec/core/resources/blocking_pipe_bisect_spec.rb_'], 1)

zombie_process = RSpecChildProcess.new(Process.pid).zombie_process
expect(zombie_process).to eq([]), <<-MSG
Expected no zombie processes got #{zombie_process.count}:
#{zombie_process}
MSG
end
end

class RSpecChildProcess
Ps = Struct.new(:pid, :ppid, :state, :command)

def initialize(pid)
@list = child_process_list(pid)
end

def zombie_process
@list.select { |child_process| child_process.state =~ /Z/ }
end

private

def child_process_list(pid)
childs_process_list = []
ps_pipe = `ps -o pid=,ppid=,state=,args= | grep #{pid}`

ps_pipe.split(/\n/).map do |line|
ps_part = line.lstrip.split(/\s+/)

next unless ps_part[1].to_i == pid

child_process = Ps.new
child_process.pid = ps_part[0]
child_process.ppid = ps_part[1]
child_process.state = ps_part[2]
child_process.command = ps_part[3..-1].join(' ')

childs_process_list << child_process
end
childs_process_list
end
end
end
end

0 comments on commit eb4a550

Please sign in to comment.