async-container 0.16.4 → 0.16.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (56) hide show
  1. checksums.yaml +4 -4
  2. data/lib/async/container.rb +0 -1
  3. data/lib/async/container/best.rb +9 -3
  4. data/lib/async/container/channel.rb +13 -0
  5. data/lib/async/container/controller.rb +49 -25
  6. data/lib/async/container/error.rb +21 -0
  7. data/lib/async/container/forked.rb +5 -1
  8. data/lib/async/container/generic.rb +57 -19
  9. data/lib/async/container/group.rb +19 -2
  10. data/lib/async/container/hybrid.rb +16 -2
  11. data/lib/async/container/keyed.rb +12 -0
  12. data/lib/async/container/notify.rb +4 -5
  13. data/lib/async/container/notify/client.rb +16 -1
  14. data/lib/async/container/notify/console.rb +8 -21
  15. data/lib/async/container/notify/pipe.rb +8 -22
  16. data/lib/async/container/notify/server.rb +0 -1
  17. data/lib/async/container/notify/socket.rb +14 -1
  18. data/lib/async/container/process.rb +28 -2
  19. data/lib/async/container/statistics.rb +16 -0
  20. data/lib/async/container/thread.rb +42 -6
  21. data/lib/async/container/threaded.rb +5 -1
  22. data/lib/async/container/version.rb +1 -1
  23. metadata +13 -88
  24. data/.editorconfig +0 -6
  25. data/.github/workflows/development.yml +0 -36
  26. data/.gitignore +0 -21
  27. data/.rspec +0 -3
  28. data/.travis.yml +0 -21
  29. data/.yardopts +0 -1
  30. data/Gemfile +0 -19
  31. data/Guardfile +0 -14
  32. data/README.md +0 -140
  33. data/Rakefile +0 -8
  34. data/async-container.gemspec +0 -34
  35. data/examples/async.rb +0 -22
  36. data/examples/channel.rb +0 -45
  37. data/examples/channels/client.rb +0 -103
  38. data/examples/container.rb +0 -33
  39. data/examples/isolate.rb +0 -36
  40. data/examples/minimal.rb +0 -94
  41. data/examples/test.rb +0 -51
  42. data/examples/threads.rb +0 -25
  43. data/examples/title.rb +0 -13
  44. data/examples/udppipe.rb +0 -35
  45. data/spec/async/container/controller_spec.rb +0 -105
  46. data/spec/async/container/dots.rb +0 -34
  47. data/spec/async/container/forked_spec.rb +0 -61
  48. data/spec/async/container/hybrid_spec.rb +0 -36
  49. data/spec/async/container/notify/notify.rb +0 -19
  50. data/spec/async/container/notify/pipe_spec.rb +0 -48
  51. data/spec/async/container/notify_spec.rb +0 -56
  52. data/spec/async/container/shared_examples.rb +0 -80
  53. data/spec/async/container/signal_spec.rb +0 -66
  54. data/spec/async/container/threaded_spec.rb +0 -35
  55. data/spec/async/container_spec.rb +0 -41
  56. data/spec/spec_helper.rb +0 -21
data/examples/isolate.rb DELETED
@@ -1,36 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # We define end of life-cycle in terms of "Interrupt" (SIGINT), "Terminate" (SIGTERM) and "Kill" (SIGKILL, does not invoke user code).
4
- class Terminate < Interrupt
5
- end
6
-
7
- class Isolate
8
- def initialize(&block)
9
-
10
- end
11
- end
12
-
13
-
14
- parent = Isolate.new do |parent|
15
- preload_user_code
16
- server = bind_socket
17
- children = 4.times.map do
18
- Isolate.new do |worker|
19
- app = load_user_application
20
- worker.ready!
21
- server.accept do |peer|
22
- app.handle_request(peer)
23
- end
24
- end
25
- end
26
- while status = parent.wait
27
- # Status is not just exit status of process but also can be `:ready` or something else.
28
- end
29
- end
30
-
31
- # Similar to Process.wait(pid)
32
- status = parent.wait
33
- # Life cycle controls
34
- parent.interrupt!
35
- parent.terminate!
36
- parent.kill!
data/examples/minimal.rb DELETED
@@ -1,94 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- class Threaded
4
- def initialize(&block)
5
- @channel = Channel.new
6
- @thread = Thread.new(&block)
7
-
8
- @waiter = Thread.new do
9
- begin
10
- @thread.join
11
- rescue Exception => error
12
- finished(error)
13
- else
14
- finished
15
- end
16
- end
17
- end
18
-
19
- attr :channel
20
-
21
- def close
22
- self.terminate!
23
- self.wait
24
- ensure
25
- @channel.close
26
- end
27
-
28
- def interrupt!
29
- @thread.raise(Interrupt)
30
- end
31
-
32
- def terminate!
33
- @thread.raise(Terminate)
34
- end
35
-
36
- def wait
37
- if @waiter
38
- @waiter.join
39
- @waiter = nil
40
- end
41
-
42
- @status
43
- end
44
-
45
- protected
46
-
47
- def finished(error = nil)
48
- @status = Status.new(error)
49
- @channel.out.close
50
- end
51
- end
52
-
53
- class Forked
54
- def initialize(&block)
55
- @channel = Channel.new
56
- @status = nil
57
-
58
- @pid = Process.fork do
59
- Signal.trap(:INT) {raise Interrupt}
60
- Signal.trap(:INT) {raise Terminate}
61
-
62
- @channel.in.close
63
-
64
- yield
65
- end
66
-
67
- @channel.out.close
68
- end
69
-
70
- attr :channel
71
-
72
- def close
73
- self.terminate!
74
- self.wait
75
- ensure
76
- @channel.close
77
- end
78
-
79
- def interrupt!
80
- Process.kill(:INT, @pid)
81
- end
82
-
83
- def terminate!
84
- Process.kill(:TERM, @pid)
85
- end
86
-
87
- def wait
88
- unless @status
89
- _pid, @status = ::Process.wait(@pid)
90
- end
91
-
92
- @status
93
- end
94
- end
data/examples/test.rb DELETED
@@ -1,51 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative 'group'
4
- require_relative 'thread'
5
- require_relative 'process'
6
-
7
- group = Async::Container::Group.new
8
-
9
- thread_monitor = Fiber.new do
10
- while true
11
- thread = Async::Container::Thread.fork do |instance|
12
- if rand < 0.2
13
- raise "Random Failure!"
14
- end
15
-
16
- instance.send(ready: true, status: "Started Thread")
17
-
18
- sleep(1)
19
- end
20
-
21
- status = group.wait_for(thread) do |message|
22
- puts "Thread message: #{message}"
23
- end
24
-
25
- puts "Thread status: #{status}"
26
- end
27
- end.resume
28
-
29
- process_monitor = Fiber.new do
30
- while true
31
- # process = Async::Container::Process.fork do |instance|
32
- # if rand < 0.2
33
- # raise "Random Failure!"
34
- # end
35
- #
36
- # instance.send(ready: true, status: "Started Process")
37
- #
38
- # sleep(1)
39
- # end
40
-
41
- process = Async::Container::Process.spawn('bash -c "sleep 1; echo foobar; sleep 1; exit -1"')
42
-
43
- status = group.wait_for(process) do |message|
44
- puts "Process message: #{message}"
45
- end
46
-
47
- puts "Process status: #{status}"
48
- end
49
- end.resume
50
-
51
- group.wait
data/examples/threads.rb DELETED
@@ -1,25 +0,0 @@
1
- #!/usr/bin/env ruby
2
- # frozen_string_literal: true
3
-
4
- puts "Process pid: #{Process.pid}"
5
-
6
- threads = 10.times.collect do
7
- Thread.new do
8
- begin
9
- sleep
10
- rescue Exception
11
- puts "Thread: #{$!}"
12
- end
13
- end
14
- end
15
-
16
- while true
17
- begin
18
- threads.each(&:join)
19
- exit(0)
20
- rescue Exception
21
- puts "Join: #{$!}"
22
- end
23
- end
24
-
25
- puts "Done"
data/examples/title.rb DELETED
@@ -1,13 +0,0 @@
1
- #!/usr/bin/env ruby
2
- # frozen_string_literal: true
3
-
4
- Process.setproctitle "Preparing for sleep..."
5
-
6
- 10.times do |i|
7
- puts "Counting sheep #{i}"
8
- Process.setproctitle "Counting sheep #{i}"
9
-
10
- sleep 10
11
- end
12
-
13
- puts "Zzzzzzz"
data/examples/udppipe.rb DELETED
@@ -1,35 +0,0 @@
1
- #!/usr/bin/env ruby
2
- # frozen_string_literal: true
3
-
4
- require 'async/io'
5
- require 'async/io/endpoint'
6
- require 'async/io/unix_endpoint'
7
-
8
- @endpoint = Async::IO::Endpoint.unix("/tmp/notify-test.sock", Socket::SOCK_DGRAM)
9
- # address = Async::IO::Address.udp("127.0.0.1", 6778)
10
- # @endpoint = Async::IO::AddressEndpoint.new(address)
11
-
12
- def server
13
- @endpoint.bind do |server|
14
- puts "Receiving..."
15
- packet, address = server.recvfrom(512)
16
-
17
- puts "Received: #{packet} from #{address}"
18
- end
19
- end
20
-
21
- def client(data = "Hello World!")
22
- @endpoint.connect do |peer|
23
- puts "Sending: #{data}"
24
- peer.send(data)
25
- puts "Sent!"
26
- end
27
- end
28
-
29
- Async do |task|
30
- server_task = task.async do
31
- server
32
- end
33
-
34
- client
35
- end
@@ -1,105 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # Copyright, 2019, by Samuel G. D. Williams. <http://www.codeotaku.com>
4
- #
5
- # Permission is hereby granted, free of charge, to any person obtaining a copy
6
- # of this software and associated documentation files (the "Software"), to deal
7
- # in the Software without restriction, including without limitation the rights
8
- # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- # copies of the Software, and to permit persons to whom the Software is
10
- # furnished to do so, subject to the following conditions:
11
- #
12
- # The above copyright notice and this permission notice shall be included in
13
- # all copies or substantial portions of the Software.
14
- #
15
- # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
- # THE SOFTWARE.
22
-
23
- require "async/container/controller"
24
-
25
- RSpec.describe Async::Container::Controller do
26
- describe '#reload' do
27
- it "can reuse keyed child" do
28
- input, output = IO.pipe
29
-
30
- subject.instance_variable_set(:@output, output)
31
-
32
- def subject.setup(container)
33
- container.spawn(key: "test") do |instance|
34
- instance.ready!
35
-
36
- sleep(0.2 * QUANTUM)
37
-
38
- @output.write(".")
39
- @output.flush
40
-
41
- sleep(0.4 * QUANTUM)
42
- end
43
-
44
- container.spawn do |instance|
45
- instance.ready!
46
-
47
- sleep(0.3 * QUANTUM)
48
-
49
- @output.write(",")
50
- @output.flush
51
- end
52
- end
53
-
54
- subject.start
55
- expect(input.read(2)).to be == ".,"
56
-
57
- subject.reload
58
-
59
- expect(input.read(1)).to be == ","
60
- subject.wait
61
- end
62
- end
63
-
64
- describe '#start' do
65
- it "can start up a container" do
66
- expect(subject).to receive(:setup)
67
-
68
- subject.start
69
-
70
- expect(subject).to be_running
71
- expect(subject.container).to_not be_nil
72
-
73
- subject.stop
74
-
75
- expect(subject).to_not be_running
76
- expect(subject.container).to be_nil
77
- end
78
-
79
- it "can spawn a reactor" do
80
- def subject.setup(container)
81
- container.async do |task|
82
- task.sleep 1
83
- end
84
- end
85
-
86
- subject.start
87
-
88
- statistics = subject.container.statistics
89
-
90
- expect(statistics.spawns).to be == 1
91
-
92
- subject.stop
93
- end
94
-
95
- it "propagates exceptions" do
96
- def subject.setup(container)
97
- raise "Boom!"
98
- end
99
-
100
- expect do
101
- subject.run
102
- end.to raise_exception(Async::Container::InitializationError)
103
- end
104
- end
105
- end
@@ -1,34 +0,0 @@
1
- #!/usr/bin/env ruby
2
- # frozen_string_literal: true
3
-
4
- require_relative '../../../lib/async/container/controller'
5
- require_relative '../../../lib/async/container/forked'
6
-
7
- Console.logger.debug!
8
-
9
- class Dots < Async::Container::Controller
10
- def setup(container)
11
- container.run(name: "dots", count: 1, restart: true) do |instance|
12
- instance.ready!
13
-
14
- sleep 1
15
-
16
- $stdout.write "."
17
- $stdout.flush
18
-
19
- sleep
20
- rescue Async::Container::Interrupt
21
- $stdout.write("I")
22
- rescue Async::Container::Terminate
23
- $stdout.write("T")
24
- end
25
- end
26
- end
27
-
28
- controller = Dots.new
29
-
30
- begin
31
- controller.run
32
- ensure
33
- $stderr.puts $!
34
- end
@@ -1,61 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # Copyright, 2018, by Samuel G. D. Williams. <http://www.codeotaku.com>
4
- #
5
- # Permission is hereby granted, free of charge, to any person obtaining a copy
6
- # of this software and associated documentation files (the "Software"), to deal
7
- # in the Software without restriction, including without limitation the rights
8
- # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- # copies of the Software, and to permit persons to whom the Software is
10
- # furnished to do so, subject to the following conditions:
11
- #
12
- # The above copyright notice and this permission notice shall be included in
13
- # all copies or substantial portions of the Software.
14
- #
15
- # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
- # THE SOFTWARE.
22
-
23
- require "async/container"
24
- require "async/container/forked"
25
-
26
- require_relative 'shared_examples'
27
-
28
- RSpec.describe Async::Container::Forked, if: Async::Container.fork? do
29
- subject {described_class.new}
30
-
31
- it_behaves_like Async::Container
32
-
33
- it "can restart child" do
34
- trigger = IO.pipe
35
- pids = IO.pipe
36
-
37
- thread = Thread.new do
38
- subject.async(restart: true) do
39
- trigger.first.gets
40
- pids.last.puts Process.pid.to_s
41
- end
42
-
43
- subject.wait
44
- end
45
-
46
- 3.times do
47
- trigger.last.puts "die"
48
- _child_pid = pids.first.gets
49
- end
50
-
51
- thread.kill
52
- thread.join
53
-
54
- expect(subject.statistics.spawns).to be == 1
55
- expect(subject.statistics.restarts).to be == 2
56
- end
57
-
58
- it "should be multiprocess" do
59
- expect(described_class).to be_multiprocess
60
- end
61
- end