Skip to content

Commit 74b0c20

Browse files
committed
Explicit specification of graceful shutdown behaviour.
1 parent db97f98 commit 74b0c20

File tree

4 files changed

+81
-31
lines changed

4 files changed

+81
-31
lines changed

examples/async.rb

Lines changed: 0 additions & 25 deletions
This file was deleted.

examples/grace/server.rb

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
#!/usr/bin/env ruby
2+
# frozen_string_literal: true
3+
4+
# Released under the MIT License.
5+
# Copyright, 2024, by Samuel Williams.
6+
7+
require '../../lib/async/container'
8+
require 'async/io/host_endpoint'
9+
10+
Console.logger.debug!
11+
12+
module SignalWrapper
13+
def self.trap(signal, &block)
14+
signal = signal
15+
16+
original = Signal.trap(signal) do
17+
::Signal.trap(signal, original)
18+
block.call
19+
end
20+
end
21+
end
22+
23+
class Controller < Async::Container::Controller
24+
def initialize(...)
25+
super
26+
27+
@endpoint = Async::IO::Endpoint.tcp("localhost", 8080)
28+
@bound_endpoint = nil
29+
end
30+
31+
def start
32+
Console.debug(self) {"Binding to #{@endpoint}"}
33+
@bound_endpoint = Sync{@endpoint.bound}
34+
35+
super
36+
end
37+
38+
def setup(container)
39+
container.run count: 2, restart: true do |instance|
40+
SignalWrapper.trap(:INT) do
41+
Console.debug(self) {"Closing bound instance..."}
42+
@bound_endpoint.close
43+
end
44+
45+
Sync do |task|
46+
Console.info(self) {"Starting bound instance..."}
47+
48+
instance.ready!
49+
50+
@bound_endpoint.accept do |peer|
51+
while true
52+
peer.write("#{Time.now.to_s.rjust(32)}: Hello World\n")
53+
sleep 1
54+
end
55+
end
56+
end
57+
end
58+
end
59+
60+
def stop(graceful = true)
61+
super
62+
63+
if @bound_endpoint
64+
@bound_endpoint.close
65+
@bound_endpoint = nil
66+
end
67+
end
68+
end
69+
70+
controller = Controller.new
71+
72+
controller.run

lib/async/container/controller.rb

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ class Controller
2222

2323
# Initialize the controller.
2424
# @parameter notify [Notify::Client] A client used for process readiness notifications.
25-
def initialize(notify: Notify.open!, container_class: Container)
25+
def initialize(notify: Notify.open!, container_class: Container, graceful: true)
2626
@container = nil
2727
@container_class = container_class
2828

@@ -35,6 +35,8 @@ def initialize(notify: Notify.open!, container_class: Container)
3535
trap(SIGHUP) do
3636
self.restart
3737
end
38+
39+
@graceful = graceful
3840
end
3941

4042
# The state of the controller.
@@ -96,7 +98,7 @@ def start
9698

9799
# Stop the container if it's running.
98100
# @parameter graceful [Boolean] Whether to give the children instances time to shut down or to kill them immediately.
99-
def stop(graceful = true)
101+
def stop(graceful = @graceful)
100102
@container&.stop(graceful)
101103
@container = nil
102104
end
@@ -130,7 +132,7 @@ def restart
130132
if container.failed?
131133
@notify&.error!("Container failed to start!")
132134

133-
container.stop
135+
container.stop(false)
134136

135137
raise SetupError, container
136138
end
@@ -142,7 +144,7 @@ def restart
142144

143145
if old_container
144146
Console.logger.debug(self, "Stopping old container...")
145-
old_container&.stop
147+
old_container&.stop(@graceful)
146148
end
147149

148150
@notify&.ready!
@@ -211,11 +213,11 @@ def run
211213
end
212214
end
213215
rescue Interrupt
214-
self.stop(true)
216+
self.stop
215217
rescue Terminate
216218
self.stop(false)
217219
ensure
218-
self.stop(true)
220+
self.stop(false)
219221

220222
# Restore the interrupt handler:
221223
Signal.trap(:INT, interrupt_action)

lib/async/container/group.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,7 @@ def wait_for(channel)
133133
protected
134134

135135
def wait_for_children(duration = nil)
136+
Console.debug(self, "Waiting for children...", duration: duration)
136137
if !@running.empty?
137138
# Maybe consider using a proper event loop here:
138139
readable, _, _ = ::IO.select(@running.keys, nil, nil, duration)

0 commit comments

Comments
 (0)