async-container 0.16.3 → 0.16.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) 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 +41 -17
  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 +51 -13
  9. data/lib/async/container/group.rb +22 -14
  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 +9 -22
  15. data/lib/async/container/notify/pipe.rb +7 -21
  16. data/lib/async/container/notify/server.rb +1 -2
  17. data/lib/async/container/notify/socket.rb +14 -1
  18. data/lib/async/container/process.rb +26 -0
  19. data/lib/async/container/statistics.rb +16 -0
  20. data/lib/async/container/thread.rb +42 -4
  21. data/lib/async/container/threaded.rb +5 -1
  22. data/lib/async/container/version.rb +1 -1
  23. metadata +12 -83
  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 -106
  46. data/spec/async/container/forked_spec.rb +0 -61
  47. data/spec/async/container/hybrid_spec.rb +0 -36
  48. data/spec/async/container/notify/notify.rb +0 -19
  49. data/spec/async/container/notify/pipe_spec.rb +0 -48
  50. data/spec/async/container/notify_spec.rb +0 -56
  51. data/spec/async/container/shared_examples.rb +0 -80
  52. data/spec/async/container/threaded_spec.rb +0 -35
  53. data/spec/async/container_spec.rb +0 -41
  54. data/spec/spec_helper.rb +0 -15
@@ -27,8 +27,12 @@ require_relative 'notify/pipe'
27
27
 
28
28
  module Async
29
29
  module Container
30
+ # Represents a running child process from the point of view of the parent container.
30
31
  class Process < Channel
32
+ # Represents a running child process from the point of view of the child process.
31
33
  class Instance < Notify::Pipe
34
+ # Wrap an instance around the {Process} instance from within the forked child.
35
+ # @parameter process [Process] The process intance to wrap.
32
36
  def self.for(process)
33
37
  instance = self.new(process.out)
34
38
 
@@ -46,16 +50,22 @@ module Async
46
50
  @name = nil
47
51
  end
48
52
 
53
+ # Set the process title to the specified value.
54
+ # @parameter value [String] The name of the process.
49
55
  def name= value
50
56
  if @name = value
51
57
  ::Process.setproctitle(@name)
52
58
  end
53
59
  end
54
60
 
61
+ # The name of the process.
62
+ # @returns [String]
55
63
  def name
56
64
  @name
57
65
  end
58
66
 
67
+ # Replace the current child process with a different one. Forwards arguments and options to {::Process.exec}.
68
+ # This method replaces the child process with the new executable, thus this method never returns.
59
69
  def exec(*arguments, ready: true, **options)
60
70
  if ready
61
71
  self.ready!(status: "(exec)") if ready
@@ -63,10 +73,13 @@ module Async
63
73
  self.before_spawn(arguments, options)
64
74
  end
65
75
 
76
+ # TODO prefer **options... but it doesn't support redirections on < 2.7
66
77
  ::Process.exec(*arguments, options)
67
78
  end
68
79
  end
69
80
 
81
+ # Fork a child process appropriate for a container.
82
+ # @returns [Process]
70
83
  def self.fork(**options)
71
84
  self.new(**options) do |process|
72
85
  ::Process.fork do
@@ -96,6 +109,8 @@ module Async
96
109
  # end
97
110
  # end
98
111
 
112
+ # Initialize the process.
113
+ # @parameter name [String] The name to use for the child process.
99
114
  def initialize(name: nil)
100
115
  super()
101
116
 
@@ -109,6 +124,8 @@ module Async
109
124
  self.close_write
110
125
  end
111
126
 
127
+ # Set the name of the process.
128
+ # Invokes {::Process.setproctitle} if invoked in the child process.
112
129
  def name= value
113
130
  @name = value
114
131
 
@@ -116,12 +133,17 @@ module Async
116
133
  ::Process.setproctitle(@name) if @pid.nil?
117
134
  end
118
135
 
136
+ # The name of the process.
137
+ # @attribute [String]
119
138
  attr :name
120
139
 
140
+ # A human readable representation of the process.
141
+ # @returns [String]
121
142
  def to_s
122
143
  "\#<#{self.class} #{@name}>"
123
144
  end
124
145
 
146
+ # Invoke {#terminate!} and then {#wait} for the child process to exit.
125
147
  def close
126
148
  self.terminate!
127
149
  self.wait
@@ -129,18 +151,22 @@ module Async
129
151
  super
130
152
  end
131
153
 
154
+ # Send `SIGINT` to the child process.
132
155
  def interrupt!
133
156
  unless @status
134
157
  ::Process.kill(:INT, @pid)
135
158
  end
136
159
  end
137
160
 
161
+ # Send `SIGTERM` to the child process.
138
162
  def terminate!
139
163
  unless @status
140
164
  ::Process.kill(:TERM, @pid)
141
165
  end
142
166
  end
143
167
 
168
+ # Wait for the child process to exit.
169
+ # @returns [::Process::Status] The process exit status.
144
170
  def wait
145
171
  if @pid && @status.nil?
146
172
  _, @status = ::Process.wait2(@pid, ::Process::WNOHANG)
@@ -24,6 +24,7 @@ require 'async/reactor'
24
24
 
25
25
  module Async
26
26
  module Container
27
+ # Tracks various statistics relating to child instances in a container.
27
28
  class Statistics
28
29
  def initialize
29
30
  @spawns = 0
@@ -31,26 +32,41 @@ module Async
31
32
  @failures = 0
32
33
  end
33
34
 
35
+ # How many child instances have been spawned.
36
+ # @attribute [Integer]
34
37
  attr :spawns
38
+
39
+ # How many child instances have been restarted.
40
+ # @attribute [Integer]
35
41
  attr :restarts
42
+
43
+ # How many child instances have failed.
44
+ # @attribute [Integer]
36
45
  attr :failures
37
46
 
47
+ # Increment the number of spawns by 1.
38
48
  def spawn!
39
49
  @spawns += 1
40
50
  end
41
51
 
52
+ # Increment the number of restarts by 1.
42
53
  def restart!
43
54
  @restarts += 1
44
55
  end
45
56
 
57
+ # Increment the number of failures by 1.
46
58
  def failure!
47
59
  @failures += 1
48
60
  end
49
61
 
62
+ # Whether there have been any failures.
63
+ # @returns [Boolean] If the failure count is greater than 0.
50
64
  def failed?
51
65
  @failures > 0
52
66
  end
53
67
 
68
+ # Append another statistics instance into this one.
69
+ # @parameter other [Statistics] The statistics to append.
54
70
  def << other
55
71
  @spawns += other.spawns
56
72
  @restarts += other.restarts
@@ -21,20 +21,29 @@
21
21
  # THE SOFTWARE.
22
22
 
23
23
  require_relative 'channel'
24
+ require_relative 'error'
24
25
  require_relative 'notify/pipe'
25
26
 
26
27
  require 'async/logger'
27
28
 
28
29
  module Async
29
30
  module Container
31
+ # Represents a running child thread from the point of view of the parent container.
30
32
  class Thread < Channel
33
+ # Used to propagate the exit status of a child process invoked by {Instance#exec}.
31
34
  class Exit < Exception
35
+ # Initialize the exit status.
36
+ # @parameter status [::Process::Status] The process exit status.
32
37
  def initialize(status)
33
38
  @status = status
34
39
  end
35
40
 
41
+ # The process exit status.
42
+ # @attribute [::Process::Status]
36
43
  attr :status
37
44
 
45
+ # The process exit status if it was an error.
46
+ # @returns [::Process::Status | Nil]
38
47
  def error
39
48
  unless status.success?
40
49
  status
@@ -42,7 +51,10 @@ module Async
42
51
  end
43
52
  end
44
53
 
54
+ # Represents a running child thread from the point of view of the child thread.
45
55
  class Instance < Notify::Pipe
56
+ # Wrap an instance around the {Thread} instance from within the threaded child.
57
+ # @parameter thread [Thread] The thread intance to wrap.
46
58
  def self.for(thread)
47
59
  instance = self.new(thread.out)
48
60
 
@@ -56,14 +68,20 @@ module Async
56
68
  super
57
69
  end
58
70
 
71
+ # Set the name of the thread.
72
+ # @parameter value [String] The name to set.
59
73
  def name= value
60
74
  @thread.name = value
61
75
  end
62
76
 
77
+ # Get the name of the thread.
78
+ # @returns [String]
63
79
  def name
64
80
  @thread.name
65
81
  end
66
82
 
83
+ # Execute a child process using {::Process.spawn}. In order to simulate {::Process.exec}, an {Exit} instance is raised to propagage exit status.
84
+ # This creates the illusion that this method does not return (normally).
67
85
  def exec(*arguments, ready: true, **options)
68
86
  if ready
69
87
  self.ready!(status: "(spawn)") if ready
@@ -90,6 +108,8 @@ module Async
90
108
  end
91
109
  end
92
110
 
111
+ # Initialize the thread.
112
+ # @parameter name [String] The name to use for the child thread.
93
113
  def initialize(name: nil)
94
114
  super()
95
115
 
@@ -115,18 +135,25 @@ module Async
115
135
  end
116
136
  end
117
137
 
138
+ # Set the name of the thread.
139
+ # @parameter value [String] The name to set.
118
140
  def name= value
119
- @thread.name = name
141
+ @thread.name = value
120
142
  end
121
143
 
144
+ # Get the name of the thread.
145
+ # @returns [String]
122
146
  def name
123
147
  @thread.name
124
148
  end
125
149
 
150
+ # A human readable representation of the thread.
151
+ # @returns [String]
126
152
  def to_s
127
153
  "\#<#{self.class} #{@thread.name}>"
128
154
  end
129
155
 
156
+ # Invoke {#terminate!} and then {#wait} for the child thread to exit.
130
157
  def close
131
158
  self.terminate!
132
159
  self.wait
@@ -134,14 +161,18 @@ module Async
134
161
  super
135
162
  end
136
163
 
164
+ # Raise {Interrupt} in the child thread.
137
165
  def interrupt!
138
166
  @thread.raise(Interrupt)
139
167
  end
140
168
 
169
+ # Raise {Terminate} in the child thread.
141
170
  def terminate!
142
171
  @thread.raise(Terminate)
143
172
  end
144
173
 
174
+ # Wait for the thread to exit and return he exit status.
175
+ # @returns [Status]
145
176
  def wait
146
177
  if @waiter
147
178
  @waiter.join
@@ -151,15 +182,21 @@ module Async
151
182
  return @status
152
183
  end
153
184
 
185
+ # A pseudo exit-status wrapper.
154
186
  class Status
155
- def initialize(result = nil)
156
- @result = result
187
+ # Initialise the status.
188
+ # @parameter error [::Process::Status] The exit status of the child thread.
189
+ def initialize(error = nil)
190
+ @error = error
157
191
  end
158
192
 
193
+ # Whether the status represents a successful outcome.
194
+ # @returns [Boolean]
159
195
  def success?
160
- @result.nil?
196
+ @error.nil?
161
197
  end
162
198
 
199
+ # A human readable representation of the status.
163
200
  def to_s
164
201
  "\#<#{self.class} #{success? ? "success" : "failure"}>"
165
202
  end
@@ -167,6 +204,7 @@ module Async
167
204
 
168
205
  protected
169
206
 
207
+ # Invoked by the @waiter thread to indicate the outcome of the child thread.
170
208
  def finished(error = nil)
171
209
  if error
172
210
  Async.logger.error(self) {error}
@@ -24,13 +24,17 @@ require_relative 'generic'
24
24
  require_relative 'thread'
25
25
 
26
26
  module Async
27
- # Manages a reactor within one or more threads.
28
27
  module Container
28
+ # A multi-thread container which uses {Thread.fork}.
29
29
  class Threaded < Generic
30
+ # Indicates that this is not a multi-process container.
30
31
  def self.multiprocess?
31
32
  false
32
33
  end
33
34
 
35
+ # Start a named child thread and execute the provided block in it.
36
+ # @parameter name [String] The name (title) of the child process.
37
+ # @parameter block [Proc] The block to execute in the child process.
34
38
  def start(name, &block)
35
39
  Thread.fork(name: name, &block)
36
40
  end
@@ -22,6 +22,6 @@
22
22
 
23
23
  module Async
24
24
  module Container
25
- VERSION = "0.16.3"
25
+ VERSION = "0.16.8"
26
26
  end
27
27
  end
metadata CHANGED
@@ -1,29 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: async-container
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.16.3
4
+ version: 0.16.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Samuel Williams
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-03-18 00:00:00.000000000 Z
11
+ date: 2020-09-19 00:00:00.000000000 Z
12
12
  dependencies:
13
- - !ruby/object:Gem::Dependency
14
- name: process-group
15
- requirement: !ruby/object:Gem::Requirement
16
- requirements:
17
- - - ">="
18
- - !ruby/object:Gem::Version
19
- version: '0'
20
- type: :runtime
21
- prerelease: false
22
- version_requirements: !ruby/object:Gem::Requirement
23
- requirements:
24
- - - ">="
25
- - !ruby/object:Gem::Version
26
- version: '0'
27
13
  - !ruby/object:Gem::Dependency
28
14
  name: async
29
15
  requirement: !ruby/object:Gem::Requirement
@@ -67,7 +53,7 @@ dependencies:
67
53
  - !ruby/object:Gem::Version
68
54
  version: '1.1'
69
55
  - !ruby/object:Gem::Dependency
70
- name: covered
56
+ name: bundler
71
57
  requirement: !ruby/object:Gem::Requirement
72
58
  requirements:
73
59
  - - ">="
@@ -81,7 +67,7 @@ dependencies:
81
67
  - !ruby/object:Gem::Version
82
68
  version: '0'
83
69
  - !ruby/object:Gem::Dependency
84
- name: bundler
70
+ name: covered
85
71
  requirement: !ruby/object:Gem::Requirement
86
72
  requirements:
87
73
  - - ">="
@@ -108,49 +94,12 @@ dependencies:
108
94
  - - "~>"
109
95
  - !ruby/object:Gem::Version
110
96
  version: '3.6'
111
- - !ruby/object:Gem::Dependency
112
- name: rake
113
- requirement: !ruby/object:Gem::Requirement
114
- requirements:
115
- - - ">="
116
- - !ruby/object:Gem::Version
117
- version: '0'
118
- type: :development
119
- prerelease: false
120
- version_requirements: !ruby/object:Gem::Requirement
121
- requirements:
122
- - - ">="
123
- - !ruby/object:Gem::Version
124
- version: '0'
125
- description: "\t\tProvides containers for servers which provide concurrency policies,
126
- e.g. threads, processes.\n"
97
+ description:
127
98
  email:
128
- - samuel.williams@oriontransfer.co.nz
129
99
  executables: []
130
100
  extensions: []
131
101
  extra_rdoc_files: []
132
102
  files:
133
- - ".editorconfig"
134
- - ".github/workflows/development.yml"
135
- - ".gitignore"
136
- - ".rspec"
137
- - ".travis.yml"
138
- - ".yardopts"
139
- - Gemfile
140
- - Guardfile
141
- - README.md
142
- - Rakefile
143
- - async-container.gemspec
144
- - examples/async.rb
145
- - examples/channel.rb
146
- - examples/channels/client.rb
147
- - examples/container.rb
148
- - examples/isolate.rb
149
- - examples/minimal.rb
150
- - examples/test.rb
151
- - examples/threads.rb
152
- - examples/title.rb
153
- - examples/udppipe.rb
154
103
  - lib/async/container.rb
155
104
  - lib/async/container/best.rb
156
105
  - lib/async/container/channel.rb
@@ -172,29 +121,19 @@ files:
172
121
  - lib/async/container/thread.rb
173
122
  - lib/async/container/threaded.rb
174
123
  - lib/async/container/version.rb
175
- - spec/async/container/controller_spec.rb
176
- - spec/async/container/forked_spec.rb
177
- - spec/async/container/hybrid_spec.rb
178
- - spec/async/container/notify/notify.rb
179
- - spec/async/container/notify/pipe_spec.rb
180
- - spec/async/container/notify_spec.rb
181
- - spec/async/container/shared_examples.rb
182
- - spec/async/container/threaded_spec.rb
183
- - spec/async/container_spec.rb
184
- - spec/spec_helper.rb
185
124
  homepage: https://github.com/socketry/async-container
186
125
  licenses:
187
126
  - MIT
188
127
  metadata: {}
189
- post_install_message:
128
+ post_install_message:
190
129
  rdoc_options: []
191
130
  require_paths:
192
131
  - lib
193
132
  required_ruby_version: !ruby/object:Gem::Requirement
194
133
  requirements:
195
- - - "~>"
134
+ - - ">="
196
135
  - !ruby/object:Gem::Version
197
- version: '2.0'
136
+ version: '2.5'
198
137
  required_rubygems_version: !ruby/object:Gem::Requirement
199
138
  requirements:
200
139
  - - ">="
@@ -202,17 +141,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
202
141
  version: '0'
203
142
  requirements: []
204
143
  rubygems_version: 3.1.2
205
- signing_key:
144
+ signing_key:
206
145
  specification_version: 4
207
- summary: Async is an asynchronous I/O framework based on nio4r.
208
- test_files:
209
- - spec/async/container/controller_spec.rb
210
- - spec/async/container/forked_spec.rb
211
- - spec/async/container/hybrid_spec.rb
212
- - spec/async/container/notify/notify.rb
213
- - spec/async/container/notify/pipe_spec.rb
214
- - spec/async/container/notify_spec.rb
215
- - spec/async/container/shared_examples.rb
216
- - spec/async/container/threaded_spec.rb
217
- - spec/async/container_spec.rb
218
- - spec/spec_helper.rb
146
+ summary: Abstract container-based parallelism using threads and processes where appropriate.
147
+ test_files: []