Skip to content

Commit 1672356

Browse files
justin808claude
andcommitted
Improve server process cleanup and readiness checks
- Add process group management for better child process cleanup - Add warning logging when process group kill fails with EPERM - Improve server readiness check to accept only 200-399 HTTP status codes - Reject 404 and 5xx responses as "not ready" for more reliable health checks These improvements provide better debugging visibility and reduce flaky tests by ensuring the server is truly ready before running tests. Fixes #198 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
1 parent 9a37c4c commit 1672356

File tree

1 file changed

+36
-11
lines changed

1 file changed

+36
-11
lines changed

lib/cypress_on_rails/server.rb

Lines changed: 36 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
require 'socket'
22
require 'timeout'
33
require 'fileutils'
4+
require 'net/http'
45
require 'cypress_on_rails/configuration'
56

67
module CypressOnRails
@@ -105,30 +106,54 @@ def spawn_server
105106

106107
puts "Starting Rails server: #{server_args.join(' ')}"
107108

108-
spawn(*server_args, out: $stdout, err: $stderr)
109+
@server_pid = spawn(*server_args, out: $stdout, err: $stderr, pgroup: true)
110+
@server_pgid = Process.getpgid(@server_pid)
111+
@server_pid
109112
end
110113

111114
def wait_for_server(timeout = 30)
112115
Timeout.timeout(timeout) do
113116
loop do
114-
begin
115-
TCPSocket.new(host, port).close
116-
break
117-
rescue Errno::ECONNREFUSED, Errno::EHOSTUNREACH
118-
sleep 0.1
119-
end
117+
break if server_responding?
118+
sleep 0.1
120119
end
121120
end
122121
rescue Timeout::Error
123122
raise "Rails server failed to start on #{host}:#{port} after #{timeout} seconds"
124123
end
125124

125+
def server_responding?
126+
url = "http://#{host}:#{port}"
127+
response = Net::HTTP.get_response(URI(url))
128+
# Accept 200-399 (success and redirects), reject 404 and 5xx
129+
(200..399).cover?(response.code.to_i)
130+
rescue Errno::ECONNREFUSED, Errno::EADDRNOTAVAIL, SocketError
131+
false
132+
end
133+
126134
def stop_server(pid)
127-
if pid
128-
puts "Stopping Rails server (PID: #{pid})"
129-
Process.kill('TERM', pid)
130-
Process.wait(pid)
135+
return unless pid
136+
137+
puts "Stopping Rails server (PID: #{pid})"
138+
send_term_signal
139+
Process.wait(pid)
140+
rescue Errno::ESRCH
141+
# Process already terminated
142+
end
143+
144+
def send_term_signal
145+
if @server_pgid
146+
Process.kill('TERM', -@server_pgid)
147+
else
148+
safe_kill_process('TERM', @server_pid)
131149
end
150+
rescue Errno::ESRCH, Errno::EPERM => e
151+
puts "Warning: Failed to kill process group #{@server_pgid}: #{e.message}, trying single process"
152+
safe_kill_process('TERM', @server_pid)
153+
end
154+
155+
def safe_kill_process(signal, pid)
156+
Process.kill(signal, pid) if pid
132157
rescue Errno::ESRCH
133158
# Process already terminated
134159
end

0 commit comments

Comments
 (0)