async-container 0.16.5 → 0.16.10

Sign up to get free protection for your applications and to get access to all the features.
Files changed (53) 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 +46 -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 +70 -20
  9. data/lib/async/container/group.rb +19 -4
  10. data/lib/async/container/hybrid.rb +5 -0
  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 +41 -6
  21. data/lib/async/container/threaded.rb +5 -1
  22. data/lib/async/container/version.rb +1 -1
  23. metadata +13 -84
  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/.yardopts +0 -1
  29. data/Gemfile +0 -19
  30. data/Guardfile +0 -14
  31. data/README.md +0 -140
  32. data/async-container.gemspec +0 -34
  33. data/examples/async.rb +0 -22
  34. data/examples/channel.rb +0 -45
  35. data/examples/channels/client.rb +0 -103
  36. data/examples/container.rb +0 -33
  37. data/examples/isolate.rb +0 -36
  38. data/examples/minimal.rb +0 -94
  39. data/examples/test.rb +0 -51
  40. data/examples/threads.rb +0 -25
  41. data/examples/title.rb +0 -13
  42. data/examples/udppipe.rb +0 -35
  43. data/spec/async/container/controller_spec.rb +0 -148
  44. data/spec/async/container/dots.rb +0 -29
  45. data/spec/async/container/forked_spec.rb +0 -61
  46. data/spec/async/container/hybrid_spec.rb +0 -36
  47. data/spec/async/container/notify/notify.rb +0 -19
  48. data/spec/async/container/notify/pipe_spec.rb +0 -48
  49. data/spec/async/container/notify_spec.rb +0 -56
  50. data/spec/async/container/shared_examples.rb +0 -80
  51. data/spec/async/container/threaded_spec.rb +0 -35
  52. data/spec/async/container_spec.rb +0 -41
  53. data/spec/spec_helper.rb +0 -21
data/.rspec DELETED
@@ -1,3 +0,0 @@
1
- --format documentation
2
- --warnings
3
- --require spec_helper
data/.yardopts DELETED
@@ -1 +0,0 @@
1
- --markup markdown
data/Gemfile DELETED
@@ -1,19 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- source 'https://rubygems.org'
4
-
5
- # Specify your gem's dependencies in utopia.gemspec
6
- gemspec
7
-
8
- group :development do
9
- gem 'pry'
10
- gem 'guard-rspec'
11
- gem 'guard-yard'
12
-
13
- gem 'yard'
14
- end
15
-
16
- group :test do
17
- gem 'benchmark-ips'
18
- gem 'ruby-prof', platforms: :mri
19
- end
data/Guardfile DELETED
@@ -1,14 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- directories %w(lib spec)
4
- clearing :on
5
-
6
- guard :rspec, cmd: "bundle exec rspec" do
7
- watch(%r{^spec/.+_spec\.rb$})
8
- watch(%r{^lib/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
9
- watch("spec/spec_helper.rb") { "spec" }
10
- end
11
-
12
- guard 'yard', :port => '8808' do
13
- watch(%r{^lib/(.+)\.rb$})
14
- end
data/README.md DELETED
@@ -1,140 +0,0 @@
1
- # Async::Container
2
-
3
- Provides containers which implement concurrency policy for high-level servers (and potentially clients).
4
-
5
- [![Actions Status](https://github.com/socketry/async-container/workflows/Development/badge.svg)](https://github.com/socketry/async-container/actions?workflow=Development)
6
- [![Code Climate](https://codeclimate.com/github/socketry/async-container.svg)](https://codeclimate.com/github/socketry/async-container)
7
- [![Coverage Status](https://coveralls.io/repos/socketry/async-container/badge.svg)](https://coveralls.io/r/socketry/async-container)
8
-
9
- ## Installation
10
-
11
- Add this line to your application's Gemfile:
12
-
13
- ```ruby
14
- gem "async-container"
15
- ```
16
-
17
- And then execute:
18
-
19
- $ bundle
20
-
21
- Or install it yourself as:
22
-
23
- $ gem install async
24
-
25
- ## Usage
26
-
27
- ### Container
28
-
29
- A container represents a set of child processes (or threads) which are doing work for you.
30
-
31
- ```ruby
32
- require 'async/container'
33
-
34
- Async.logger.debug!
35
-
36
- container = Async::Container.new
37
-
38
- container.async do |task|
39
- task.logger.debug "Sleeping..."
40
- task.sleep(1)
41
- task.logger.debug "Waking up!"
42
- end
43
-
44
- Async.logger.debug "Waiting for container..."
45
- container.wait
46
- Async.logger.debug "Finished."
47
- ```
48
-
49
- ### Controller
50
-
51
- The controller provides the life-cycle management for one or more containers of processes. It provides behaviour like starting, restarting, reloading and stopping. You can see some [example implementations in Falcon](https://github.com/socketry/falcon/blob/master/lib/falcon/controller/). If the process running the controller receives `SIGHUP` it will recreate the container gracefully.
52
-
53
- ```ruby
54
- require 'async/container'
55
-
56
- Async.logger.debug!
57
-
58
- class Controller < Async::Container::Controller
59
- def setup(container)
60
- container.async do |task|
61
- while true
62
- Async.logger.debug("Sleeping...")
63
- task.sleep(1)
64
- end
65
- end
66
- end
67
- end
68
-
69
- controller = Controller.new
70
-
71
- controller.run
72
-
73
- # If you send SIGHUP to this process, it will recreate the container.
74
- ```
75
-
76
- ### Signal Handling
77
-
78
- `SIGINT` is the interrupt signal. The terminal sends it to the foreground process when the user presses **ctrl-c**. The default behavior is to terminate the process, but it can be caught or ignored. The intention is to provide a mechanism for an orderly, graceful shutdown.
79
-
80
- `SIGQUIT` is the dump core signal. The terminal sends it to the foreground process when the user presses **ctrl-\**. The default behavior is to terminate the process and dump core, but it can be caught or ignored. The intention is to provide a mechanism for the user to abort the process. You can look at `SIGINT` as "user-initiated happy termination" and `SIGQUIT` as "user-initiated unhappy termination."
81
-
82
- `SIGTERM` is the termination signal. The default behavior is to terminate the process, but it also can be caught or ignored. The intention is to kill the process, gracefully or not, but to first allow it a chance to cleanup.
83
-
84
- `SIGKILL` is the kill signal. The only behavior is to kill the process, immediately. As the process cannot catch the signal, it cannot cleanup, and thus this is a signal of last resort.
85
-
86
- `SIGSTOP` is the pause signal. The only behavior is to pause the process; the signal cannot be caught or ignored. The shell uses pausing (and its counterpart, resuming via `SIGCONT`) to implement job control.
87
-
88
- ### Integration
89
-
90
- #### systemd
91
-
92
- Install a template file into `/etc/systemd/system/`:
93
-
94
- ```
95
- # my-daemon.service
96
- [Unit]
97
- Description=My Daemon
98
- AssertPathExists=/srv/
99
-
100
- [Service]
101
- Type=notify
102
- WorkingDirectory=/srv/my-daemon
103
- ExecStart=bundle exec my-daemon
104
- Nice=5
105
-
106
- [Install]
107
- WantedBy=multi-user.target
108
- ```
109
-
110
- ## Contributing
111
-
112
- 1. Fork it
113
- 2. Create your feature branch (`git checkout -b my-new-feature`)
114
- 3. Commit your changes (`git commit -am 'Add some feature'`)
115
- 4. Push to the branch (`git push origin my-new-feature`)
116
- 5. Create new Pull Request
117
-
118
- ## License
119
-
120
- Released under the MIT license.
121
-
122
- Copyright, 2017, by [Samuel G. D. Williams](http://www.codeotaku.com/samuel-williams).
123
-
124
- Permission is hereby granted, free of charge, to any person obtaining a copy
125
- of this software and associated documentation files (the "Software"), to deal
126
- in the Software without restriction, including without limitation the rights
127
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
128
- copies of the Software, and to permit persons to whom the Software is
129
- furnished to do so, subject to the following conditions:
130
-
131
- The above copyright notice and this permission notice shall be included in
132
- all copies or substantial portions of the Software.
133
-
134
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
135
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
136
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
137
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
138
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
139
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
140
- THE SOFTWARE.
@@ -1,34 +0,0 @@
1
-
2
- require_relative 'lib/async/container/version'
3
-
4
- Gem::Specification.new do |spec|
5
- spec.name = "async-container"
6
- spec.version = Async::Container::VERSION
7
- spec.authors = ["Samuel Williams"]
8
- spec.email = ["samuel.williams@oriontransfer.co.nz"]
9
- spec.description = <<-EOF
10
- Provides containers for servers which provide concurrency policies, e.g. threads, processes.
11
- EOF
12
- spec.summary = "Async is an asynchronous I/O framework based on nio4r."
13
- spec.homepage = "https://github.com/socketry/async-container"
14
- spec.license = "MIT"
15
-
16
- spec.files = `git ls-files`.split($/)
17
- spec.executables = spec.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
18
- spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
- spec.require_paths = ["lib"]
20
-
21
- spec.required_ruby_version = "~> 2.0"
22
-
23
- spec.add_runtime_dependency "process-group"
24
-
25
- spec.add_runtime_dependency "async", "~> 1.0"
26
- spec.add_runtime_dependency "async-io", "~> 1.26"
27
-
28
- spec.add_development_dependency "async-rspec", "~> 1.1"
29
-
30
- spec.add_development_dependency "covered"
31
- spec.add_development_dependency "bundler"
32
- spec.add_development_dependency "rspec", "~> 3.6"
33
- spec.add_development_dependency "bake-bundler"
34
- end
data/examples/async.rb DELETED
@@ -1,22 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'kernel/sync'
4
-
5
- class Worker
6
- def initialize(&block)
7
-
8
- end
9
- end
10
-
11
- Sync do
12
- count.times do
13
- worker = Worker.new(&block)
14
-
15
- status = worker.wait do |message|
16
-
17
- end
18
-
19
- status.success?
20
- status.failed?
21
- end
22
- end
data/examples/channel.rb DELETED
@@ -1,45 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'json'
4
-
5
- class Channel
6
- def initialize
7
- @in, @out = IO.pipe
8
- end
9
-
10
- def after_fork
11
- @out.close
12
- end
13
-
14
- def receive
15
- if data = @in.gets
16
- JSON.parse(data, symbolize_names: true)
17
- end
18
- end
19
-
20
- def send(**message)
21
- data = JSON.dump(message)
22
-
23
- @out.puts(data)
24
- end
25
- end
26
-
27
- status = Channel.new
28
-
29
- pid = fork do
30
- status.send(ready: false, status: "Initializing...")
31
-
32
- # exit(-1) # crash
33
-
34
- status.send(ready: true, status: "Initialization Complete!")
35
- end
36
-
37
- status.after_fork
38
-
39
- while message = status.receive
40
- pp message
41
- end
42
-
43
- pid, status = Process.waitpid2(pid)
44
-
45
- puts "Status: #{status}"
@@ -1,103 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'msgpack'
4
- require 'async/io'
5
- require 'async/io/stream'
6
- require 'async/container'
7
-
8
- # class Bus
9
- # def initialize
10
- #
11
- # end
12
- #
13
- # def << object
14
- # :object
15
- # end
16
- #
17
- # def [] key
18
- # return
19
- # end
20
- # end
21
- #
22
- # class Proxy < BasicObject
23
- # def initialize(bus, name)
24
- # @bus = bus
25
- # @name = name
26
- # end
27
- #
28
- # def inspect
29
- # "[Proxy #{method_missing(:inspect)}]"
30
- # end
31
- #
32
- # def method_missing(*args, &block)
33
- # @bus.invoke(@name, args, &block)
34
- # end
35
- #
36
- # def respond_to?(*args)
37
- # @bus.invoke(@name, ["respond_to?", *args])
38
- # end
39
- # end
40
- #
41
- # class Wrapper < MessagePack::Factory
42
- # def initialize(bus)
43
- # super()
44
- #
45
- # self.register_type(0x00, Object,
46
- # packer: @bus.method(:<<),
47
- # unpacker: @bus.method(:[])
48
- # )
49
- #
50
- # self.register_type(0x01, Symbol)
51
- # self.register_type(0x02, Exception,
52
- # packer: ->(exception){Marshal.dump(exception)},
53
- # unpacker: ->(data){Marshal.load(data)},
54
- # )
55
- #
56
- # self.register_type(0x03, Class,
57
- # packer: ->(klass){Marshal.dump(klass)},
58
- # unpacker: ->(data){Marshal.load(data)},
59
- # )
60
- # end
61
- # end
62
- #
63
- # class Channel
64
- # def self.pipe
65
- # input, output = Async::IO.pipe
66
- # end
67
- #
68
- # def initialize(input, output)
69
- # @input = input
70
- # @output = output
71
- # end
72
- #
73
- # def read
74
- # @input.read
75
- # end
76
- #
77
- # def write
78
- # end
79
- # end
80
-
81
- container = Async::Container.new
82
- input, output = Async::IO.pipe
83
-
84
- container.async do |instance|
85
- stream = Async::IO::Stream.new(input)
86
- output.close
87
-
88
- while message = stream.gets
89
- puts "Hello World from #{instance}: #{message}"
90
- end
91
-
92
- puts "exiting"
93
- end
94
-
95
- stream = Async::IO::Stream.new(output)
96
-
97
- 5.times do |i|
98
- stream.puts "#{i}"
99
- end
100
-
101
- stream.close
102
-
103
- container.wait
@@ -1,33 +0,0 @@
1
- #!/usr/bin/env ruby
2
- # frozen_string_literal: true
3
-
4
- require '../lib/async/container/controller'
5
- require '../lib/async/container/forked'
6
-
7
- Async.logger.debug!
8
-
9
- Async.logger.debug(self, "Starting up...")
10
-
11
- controller = Async::Container::Controller.new do |container|
12
- Async.logger.debug(self, "Setting up container...")
13
-
14
- container.run(count: 1, restart: true) do
15
- Async.logger.debug(self, "Child process started.")
16
-
17
- while true
18
- sleep 1
19
-
20
- if rand < 0.1
21
- exit(1)
22
- end
23
- end
24
- ensure
25
- Async.logger.debug(self, "Child process exiting:", $!)
26
- end
27
- end
28
-
29
- begin
30
- controller.run
31
- ensure
32
- Async.logger.debug(controller, "Parent process exiting:", $!)
33
- end
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!