Skip to content

Commit 48bea58

Browse files
committed
Queue signals while connecting to application
Otherwise we can end up with a situation where the user issues a ^C after the application has started running the command, but before we've got the worker pid. Thus the client process exits but the worker process carries on running, and output appears on the user's terminal.
1 parent 790b750 commit 48bea58

File tree

1 file changed

+27
-2
lines changed

1 file changed

+27
-2
lines changed

lib/spring/client/run.rb

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,12 @@ module Spring
55
module Client
66
class Run < Command
77
FORWARDED_SIGNALS = %w(INT QUIT USR1 USR2 INFO) & Signal.list.keys
8+
TIMEOUT = 1
9+
10+
def initialize(args)
11+
super
12+
@signal_queue = []
13+
end
814

915
def log(message)
1016
env.log "[client] #{message}"
@@ -20,6 +26,7 @@ def call
2026

2127
application, client = UNIXSocket.pair
2228

29+
queue_signals
2330
connect_to_application(client)
2431
run_command(client, application)
2532
rescue Errno::ECONNRESET
@@ -59,7 +66,12 @@ def verify_server_version
5966
def connect_to_application(client)
6067
server.send_io client
6168
send_json server, "args" => args, "default_rails_env" => default_rails_env
62-
server.gets or raise CommandNotFound
69+
70+
if IO.select([server], [], [], TIMEOUT)
71+
server.gets or raise CommandNotFound
72+
else
73+
raise "Error connecting to Spring server"
74+
end
6375
end
6476

6577
def run_command(client, application)
@@ -96,21 +108,34 @@ def run_command(client, application)
96108
application.close
97109
end
98110

111+
def queue_signals
112+
FORWARDED_SIGNALS.each do |sig|
113+
trap(sig) { @signal_queue << sig }
114+
end
115+
end
116+
99117
def forward_signals(pid)
118+
@signal_queue.each { |sig| kill sig, pid }
119+
100120
FORWARDED_SIGNALS.each do |sig|
101121
trap(sig) { forward_signal sig, pid }
102122
end
123+
rescue Errno::ESRCH
103124
end
104125

105126
def forward_signal(sig, pid)
106-
Process.kill(sig, -Process.getpgid(pid))
127+
kill(sig, pid)
107128
rescue Errno::ESRCH
108129
# If the application process is gone, then don't block the
109130
# signal on this process.
110131
trap(sig, 'DEFAULT')
111132
Process.kill(sig, Process.pid)
112133
end
113134

135+
def kill(sig, pid)
136+
Process.kill(sig, -Process.getpgid(pid))
137+
end
138+
114139
def send_json(socket, data)
115140
data = JSON.dump(data)
116141

0 commit comments

Comments
 (0)