Skip to content

Commit 269a5e8

Browse files
committed
More robust signal handling.
1 parent 5ad7b89 commit 269a5e8

File tree

3 files changed

+47
-30
lines changed

3 files changed

+47
-30
lines changed

lib/async/container/controller.rb

Lines changed: 35 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -187,47 +187,56 @@ def reload
187187
def run
188188
@notify&.status!("Initializing...")
189189

190+
with_signal_handlers do
191+
self.start
192+
193+
while @container&.running?
194+
begin
195+
@container.wait
196+
rescue SignalException => exception
197+
if handler = @signals[exception.signo]
198+
begin
199+
handler.call
200+
rescue SetupError => error
201+
Console.error(self) {error}
202+
end
203+
else
204+
raise
205+
end
206+
end
207+
end
208+
rescue Interrupt
209+
self.stop
210+
rescue Terminate
211+
self.stop(false)
212+
ensure
213+
self.stop(false)
214+
end
215+
end
216+
217+
private def with_signal_handlers
190218
# I thought this was the default... but it doesn't always raise an exception unless you do this explicitly.
191-
# We use `Thread.current.raise(...)` so that exceptions are filtered through `Thread.handle_interrupt` correctly.
219+
192220
interrupt_action = Signal.trap(:INT) do
193-
# $stderr.puts "Received INT signal, terminating...", caller
221+
# We use `Thread.current.raise(...)` so that exceptions are filtered through `Thread.handle_interrupt` correctly.
222+
# $stderr.puts "Received Interrupt signal, terminating...", caller
194223
::Thread.current.raise(Interrupt)
195224
end
196225

197226
terminate_action = Signal.trap(:TERM) do
198-
# $stderr.puts "Received TERM signal, terminating...", caller
227+
# $stderr.puts "Received Terminate signal, terminating...", caller
199228
::Thread.current.raise(Terminate)
200229
end
201230

202231
hangup_action = Signal.trap(:HUP) do
203-
# $stderr.puts "Received HUP signal, restarting...", caller
232+
# $stderr.puts "Received Hangup signal, restarting...", caller
204233
::Thread.current.raise(Hangup)
205234
end
206235

207-
self.start
208-
209-
while @container&.running?
210-
begin
211-
@container.wait
212-
rescue SignalException => exception
213-
if handler = @signals[exception.signo]
214-
begin
215-
handler.call
216-
rescue SetupError => error
217-
Console.error(self) {error}
218-
end
219-
else
220-
raise
221-
end
222-
end
236+
::Thread.handle_interrupt(SignalException => :on_blocking) do
237+
yield
223238
end
224-
rescue Interrupt
225-
self.stop
226-
rescue Terminate
227-
self.stop(false)
228239
ensure
229-
self.stop(false)
230-
231240
# Restore the interrupt handler:
232241
Signal.trap(:INT, interrupt_action)
233242
Signal.trap(:TERM, terminate_action)

lib/async/container/group.rb

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -142,11 +142,19 @@ def wait_for_children(duration = nil)
142142

143143
if !@running.empty?
144144
# Maybe consider using a proper event loop here:
145+
if ready = self.select(duration)
146+
ready.each do |io|
147+
@running[io].resume
148+
end
149+
end
150+
end
151+
end
152+
153+
def select(duration)
154+
::Thread.handle_interrupt(SignalException => :immediate) do
145155
readable, _, _ = ::IO.select(@running.keys, nil, nil, duration)
146156

147-
readable&.each do |io|
148-
@running[io].resume
149-
end
157+
return readable
150158
end
151159
end
152160

lib/async/container/process.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ def self.fork(**options)
6969
Signal.trap(:INT) {::Thread.current.raise(Interrupt)}
7070
Signal.trap(:TERM) {::Thread.current.raise(Terminate)}
7171

72-
begin
72+
::Thread.handle_interrupt(SignalException => :immediate) do
7373
yield Instance.for(process)
7474
rescue Interrupt
7575
# Graceful exit.

0 commit comments

Comments
 (0)