Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
ioquatix committed Dec 9, 2024
1 parent 9999fe1 commit 8e9e9d5
Show file tree
Hide file tree
Showing 9 changed files with 186 additions and 7 deletions.
6 changes: 6 additions & 0 deletions async-container-demo/Gemfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# frozen_string_literal: true

source "https://rubygems.org"

gem "async-container", path: "../"
gem "debug"
50 changes: 50 additions & 0 deletions async-container-demo/Gemfile.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
PATH
remote: ..
specs:
async-container (0.18.3)
async (~> 2.10)

GEM
remote: https://rubygems.org/
specs:
async (2.21.1)
console (~> 1.29)
fiber-annotation
io-event (~> 1.6, >= 1.6.5)
console (1.29.0)
fiber-annotation
fiber-local (~> 1.1)
json
date (3.4.1)
debug (1.9.2)
irb (~> 1.10)
reline (>= 0.3.8)
fiber-annotation (0.2.0)
fiber-local (1.1.0)
fiber-storage
fiber-storage (1.0.0)
io-console (0.8.0)
io-event (1.7.4)
irb (1.14.1)
rdoc (>= 4.0.0)
reline (>= 0.4.2)
json (2.9.0)
psych (5.2.1)
date
stringio
rdoc (6.8.1)
psych (>= 4.0.0)
reline (0.5.12)
io-console (~> 0.5)
stringio (3.1.2)

PLATFORMS
arm64-darwin-22
ruby

DEPENDENCIES
async-container!
debug

BUNDLED WITH
2.5.22
27 changes: 27 additions & 0 deletions async-container-demo/jobs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#!/usr/bin/env ruby
# frozen_string_literal: true

require "console"

Console.logger.debug!

class Jobs
LOG_FILE = File.join(Dir.pwd, "jobs.log")

def self.start = self.new.start

def start
Console.debug(self, "Starting jobs...")

loop do
Console.info(self, "Jobs running...")

sleep 1
end
rescue Interrupt
Console.debug(self, "Exiting jobs...")
exit
end
end

Jobs.start
56 changes: 56 additions & 0 deletions async-container-demo/start
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
#!/usr/bin/env ruby
# frozen_string_literal: true

require "async/container"
require "console"
require "debug"

# container = Async::Container.new

# container.spawn(name: "Web") do |task|
# task.exec("bundle", "exec", "web")
# end

# container.spawn(name: "Jobs") do |task|
# task.exec("bundle", "exec", "jobs")
# end

Console.logger.debug!

class WebController < Async::Container::Controller
def setup(container)
container.spawn(name: "Web") do |instance|
instance.exec("bundle", "exec", "web")
end

# container.spawn(name: "Jobs") do |instance|
# instance.exec("bundle", "exec", "jobs")
# end
end
end

class App
def self.start = self.new.start

def start
Console.debug(self, "Starting container...")

web_controller = WebController.new
web_controller.run
end
end

pid = Process.pid
pgid = Process.getpgid(pid)

Thread.new do
sleep 5
Console.debug(self, "Sending HUP signal to restart container...")
Process.kill("HUP", -pgid)

# sleep 5
# Console.debug(self, "Sending INT signal to stop container...")
# Process.kill("INT", Process.pid)
end

App.start
27 changes: 27 additions & 0 deletions async-container-demo/web
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#!/usr/bin/env ruby
# frozen_string_literal: true

require "console"

Console.logger.debug!

class Web
LOG_FILE = File.join(Dir.pwd, "web.log")

def self.start = self.new.start

def start
Console.debug(self, "Starting web...")

loop do
Console.info(self, "Web running...")

sleep 1
end
rescue Interrupt
Console.debug(self, "Exiting web...")
exit
end
end

Web.start
7 changes: 4 additions & 3 deletions lib/async/container/controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -186,17 +186,17 @@ def run
# I thought this was the default... but it doesn't always raise an exception unless you do this explicitly.
# We use `Thread.current.raise(...)` so that exceptions are filtered through `Thread.handle_interrupt` correctly.
interrupt_action = Signal.trap(:INT) do
# $stderr.puts "Received INT signal, terminating...", caller
$stderr.puts "Received INT signal, terminating...", caller
::Thread.current.raise(Interrupt)
end

terminate_action = Signal.trap(:TERM) do
# $stderr.puts "Received TERM signal, terminating...", caller
$stderr.puts "Received TERM signal, terminating...", caller
::Thread.current.raise(Terminate)
end

hangup_action = Signal.trap(:HUP) do
# $stderr.puts "Received HUP signal, restarting...", caller
$stderr.puts "Received HUP signal, restarting...", caller
::Thread.current.raise(Hangup)
end

Expand All @@ -208,6 +208,7 @@ def run
rescue SignalException => exception
if handler = @signals[exception.signo]
begin
Console.debug(self, "Invoking signal handler for #{exception.signo}...", handler: handler)
handler.call
rescue SetupError => error
Console.error(self) {error}
Expand Down
9 changes: 8 additions & 1 deletion lib/async/container/generic.rb
Original file line number Diff line number Diff line change
Expand Up @@ -107,13 +107,20 @@ def wait_until_ready
Console.debug(self) do |buffer|
buffer.puts "Waiting for ready:"
@state.each do |child, state|
buffer.puts "\t#{child.class}: #{state.inspect}"
buffer.puts "\t#{child.inspect}: #{state}"
end
end

self.sleep

if self.status?(:ready)
Console.logger.debug(self) do |buffer|
buffer.puts "All ready:"
@state.each do |child, state|
buffer.puts "\t#{child.inspect}: #{state}"
end
end

return true
end
end
Expand Down
3 changes: 2 additions & 1 deletion lib/async/container/group.rb
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,8 @@ def wait_for(channel)
protected

def wait_for_children(duration = nil)
Console.debug(self, "Waiting for children...", duration: duration)
Console.debug(self, "Waiting for children...", duration: duration, running: @running)

if !@running.empty?
# Maybe consider using a proper event loop here:
readable, _, _ = ::IO.select(@running.keys, nil, nil, duration)
Expand Down
8 changes: 6 additions & 2 deletions lib/async/container/process.rb
Original file line number Diff line number Diff line change
Expand Up @@ -122,10 +122,12 @@ def name= value

# A human readable representation of the process.
# @returns [String]
def to_s
"\#<#{self.class} #{@name}>"
def inspect
"\#<#{self.class} name=#{@name.inspect} status=#{@status.inspect} pid=#{@pid.inspect}>"
end

alias to_s inspect

# Invoke {#terminate!} and then {#wait} for the child process to exit.
def close
self.terminate!
Expand All @@ -151,6 +153,8 @@ def terminate!
# Wait for the child process to exit.
# @returns [::Process::Status] The process exit status.
def wait
$stderr.puts "Waiting for #{@pid}...", caller

if @pid && @status.nil?
_, @status = ::Process.wait2(@pid, ::Process::WNOHANG)

Expand Down

0 comments on commit 8e9e9d5

Please sign in to comment.