Skip to content

Commit

Permalink
Ensure the container is stopped if it's not correctly started. (#32)
Browse files Browse the repository at this point in the history
  • Loading branch information
ioquatix authored Mar 25, 2024
1 parent 9fb616f commit db97f98
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 6 deletions.
14 changes: 8 additions & 6 deletions lib/async/container/controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -135,18 +135,20 @@ def restart
raise SetupError, container
end

# Make this swap as atomic as possible:
# 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
end

Console.logger.debug(self, "Stopping old container...")
old_container&.stop
@notify&.ready!
rescue
ensure
# If we are leaving this function with an exception, try to kill the container:
container&.stop(false)

raise
end

# Reload the existing container. Children instances will be reloaded using `SIGHUP`.
Expand Down
28 changes: 28 additions & 0 deletions test/async/container/.bad.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#!/usr/bin/env ruby
# frozen_string_literal: true

# Released under the MIT License.
# Copyright, 2020-2022, by Samuel Williams.

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

class Bad < Async::Container::Controller
def setup(container)
container.run(name: "bad", count: 1, restart: true) do |instance|
# Deliberately missing call to `instance.ready!`:
# instance.ready!

$stdout.puts "Ready..."
$stdout.flush

sleep
ensure
$stdout.puts "Exiting..."
$stdout.flush
end
end
end

controller = Bad.new

controller.run
32 changes: 32 additions & 0 deletions test/async/container/controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,38 @@ def controller.setup(container)
end
end

with 'bad controller' do
let(:controller_path) {File.expand_path(".bad.rb", __dir__)}

let(:pipe) {IO.pipe}
let(:input) {pipe.first}
let(:output) {pipe.last}

let(:pid) {@pid}

def before
@pid = Process.spawn("bundle", "exec", controller_path, out: output)
output.close

super
end

def after
Process.kill(:TERM, @pid)
Process.wait(@pid)

super
end

it "fails to start" do
expect(input.gets).to be == "Ready...\n"

Process.kill(:INT, @pid)

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

with 'signals' do
let(:controller_path) {File.expand_path(".dots.rb", __dir__)}

Expand Down

0 comments on commit db97f98

Please sign in to comment.