Skip to content

Commit

Permalink
WIP.
Browse files Browse the repository at this point in the history
  • Loading branch information
ioquatix committed Mar 26, 2024
1 parent 2e698a1 commit f2d6234
Show file tree
Hide file tree
Showing 4 changed files with 94 additions and 81 deletions.
162 changes: 87 additions & 75 deletions lib/async/container/controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -99,83 +99,91 @@ def start
# Stop the container if it's running.
# @parameter graceful [Boolean] Whether to give the children instances time to shut down or to kill them immediately.
def stop(graceful = @graceful_stop)
@container&.stop(graceful)
@container = nil
::Thread.handle_interrupt(Interrupt => :never, Hangup => :never) do
@container&.stop(graceful)
@container = nil
end
end

# Restart the container. A new container is created, and if successful, any old container is terminated gracefully.
# This is equivalent to a blue-green deployment.
def restart
if @container
@notify&.restarting!
::Thread.handle_interrupt(Interrupt => :never, Hangup => :never) do
if @container
@notify&.restarting!

Console.logger.debug(self) {"Restarting container..."}
else
Console.logger.debug(self) {"Starting container..."}
end

Console.logger.debug(self) {"Restarting container..."}
else
Console.logger.debug(self) {"Starting container..."}
end

container = self.create_container

begin
self.setup(container)
rescue => error
@notify&.error!(error.to_s)
container = self.create_container

raise SetupError, container
end

# Wait for all child processes to enter the ready state.
Console.logger.debug(self, "Waiting for startup...")
container.wait_until_ready
Console.logger.debug(self, "Finished startup.")

if container.failed?
@notify&.error!("Container failed to start!")
begin
self.setup(container)
rescue => error
@notify&.error!(error.to_s)

raise SetupError, container
end

container.stop(false)
# Wait for all child processes to enter the ready state.
Console.logger.debug(self, "Waiting for startup...")
container.wait_until_ready
Console.logger.debug(self, "Finished startup.")

raise SetupError, container
end

# The following swap should be atomic:
old_container = @container
@container = container
container = nil

if old_container
Console.logger.debug(self, "Stopping old container...")
old_container&.stop(@graceful_stop)
if container.failed?
@notify&.error!("Container failed to start!")

container.stop(false)

raise SetupError, container
end

# The following swap should be atomic:
old_container = @container
@container = container
container = nil

if old_container
Console.logger.debug(self, "Stopping old container...")
old_container&.stop(@graceful_stop)
end

@notify&.ready!
ensure
# If we are leaving this function with an exception, try to kill the container:
container&.stop(false)
end

@notify&.ready!
ensure
# If we are leaving this function with an exception, try to kill the container:
container&.stop(false)
end

# Reload the existing container. Children instances will be reloaded using `SIGHUP`.
def reload
@notify&.reloading!

Console.logger.info(self) {"Reloading container: #{@container}..."}

begin
self.setup(@container)
rescue
raise SetupError, container
end

# Wait for all child processes to enter the ready state.
Console.logger.debug(self, "Waiting for startup...")
@container.wait_until_ready
Console.logger.debug(self, "Finished startup.")

if @container.failed?
@notify.error!("Container failed to reload!")
::Thread.handle_interrupt(Interrupt => :never, Hangup => :never) do
@notify&.reloading!

raise SetupError, @container
else
@notify&.ready!
Console.logger.info(self) {"Reloading container: #{@container}..."}

begin
self.setup(@container)
rescue
raise SetupError, container
end

# Wait for all child processes to enter the ready state.
Console.logger.debug(self, "Waiting for startup...")

@container.wait_until_ready

Console.logger.debug(self, "Finished startup.")

if @container.failed?
@notify.error!("Container failed to reload!")

raise SetupError, @container
else
@notify&.ready!
end
end
end

Expand All @@ -195,20 +203,24 @@ def run
::Thread.current.raise(Hangup)
end

self.start

while @container&.running?
begin
@container.wait
rescue SignalException => exception
if handler = @signals[exception.signo]
begin
handler.call
rescue SetupError => error
Console.logger.error(self) {error}
::Thread.handle_interrupt(Interrupt => :never, Hangup => :never) do
self.start

while @container&.running?
begin
::Thread.handle_interrupt(Interrupt => :on_blocking, Hangup => :on_blocking) do
@container.wait
end
rescue SignalException => exception
if handler = @signals[exception.signo]
begin
handler.call
rescue SetupError => error
Console.logger.error(self) {error}
end
else
raise
end
else
raise
end
end
end
Expand Down
6 changes: 5 additions & 1 deletion lib/async/container/forked.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,11 @@ def self.multiprocess?
# @parameter name [String] The name (title) of the child process.
# @parameter block [Proc] The block to execute in the child process.
def start(name, &block)
Process.fork(name: name, &block)
Process.fork(name: name) do
::Thread.handle_interrupt(Exception => :immediate) do
yield
end
end
end
end
end
Expand Down
5 changes: 1 addition & 4 deletions test/async/container/.dots.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,14 @@

require_relative '../../../lib/async/container/controller'

# Console.logger.debug!
$stdout.sync = true

class Dots < Async::Container::Controller
def setup(container)
container.run(name: "dots", count: 1, restart: true) do |instance|
instance.ready!

sleep 1

$stdout.write "."
$stdout.flush

sleep
rescue Async::Container::Interrupt
Expand Down
2 changes: 1 addition & 1 deletion test/async/container/controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ def after
it "fails to start" do
expect(input.gets).to be == "Ready...\n"

Process.kill(:INT, @pid)
Process.kill(:TERM, @pid)

expect(input.gets).to be == "Exiting...\n"
end
Expand Down

0 comments on commit f2d6234

Please sign in to comment.