lib/async/container/controller.rb in async-container-0.14.1 vs lib/async/container/controller.rb in async-container-0.15.0
- old
+ new
@@ -16,52 +16,104 @@
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
-require_relative 'terminator'
+require_relative 'error'
+require_relative 'best'
-require 'async/reactor'
+require_relative 'statistics'
module Async
module Container
+ class ContainerFailed < Error
+ def initialize(container)
+ super("Could not create container!")
+ @container = container
+ end
+
+ attr :container
+ end
+
+ # Manages the life-cycle of a container.
class Controller
- def initialize
- @attached = []
+ SIGHUP = Signal.list["HUP"]
+ DEFAULT_TIMEOUT = 2
+
+ def initialize(startup_duration: DEFAULT_TIMEOUT)
+ @container = nil
+
+ @startup_duration = startup_duration
end
- def attach(controller = nil, &block)
- if controller
- @attached << controller
+ attr :container
+
+ def create_container
+ Container.new
+ end
+
+ def setup(container)
+ end
+
+ def start
+ self.restart
+ end
+
+ def stop(graceful = true)
+ @container&.stop(graceful)
+ @container = nil
+ end
+
+ def restart(duration = @startup_duration)
+ hup_action = Signal.trap(:HUP, :IGNORE)
+ container = self.create_container
+
+ begin
+ self.setup(container)
+ rescue
+ raise ContainerFailed, container
end
- if block_given?
- @attached << Terminator.new(&block)
+ Async.logger.debug(self, "Waiting for startup...")
+ container.sleep(duration)
+ Async.logger.debug(self, "Finished startup.")
+
+ if container.failed?
+ container.stop
+
+ raise ContainerFailed, container
end
- return self
+ @container&.stop
+ @container = container
+ ensure
+ Signal.trap(:HUP, hup_action)
end
- def async(**options, &block)
- spawn(**options) do |instance|
+ def run
+ Async.logger.debug(self) {"Starting container..."}
+
+ self.start
+
+ while true
begin
- Async::Reactor.run(instance, &block)
- rescue Interrupt
- # Graceful exit.
+ @container.wait
+ rescue SignalException => exception
+ if exception.signo == SIGHUP
+ Async.logger.info(self) {"Reloading container..."}
+
+ begin
+ self.restart
+ rescue ContainerFailed => failure
+ Async.logger.error(self) {failure}
+ end
+ else
+ raise
+ end
end
end
- end
-
- def run(count: Container.processor_count, **options, &block)
- count.times do
- async(**options, &block)
- end
-
- return self
- end
-
- def stop(graceful = true)
- @attached.each(&:stop)
+ ensure
+ self.stop
end
end
end
end