async-container 0.9.0 → 0.10.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6c834b2b589e3335d182640afbda3d6a1011745158bd1d4a68ec7e06172c8f88
4
- data.tar.gz: 6fc1fd4a20dd7ebdcdc5b1350098424ea6f4fe894eca3718764c5fa920b0e66e
3
+ metadata.gz: 7e12746b238bcba194703fa7f7506771fd52a9d6cb760a55304037581562c51c
4
+ data.tar.gz: 12b70988e2901e107c93c8ca3bd3be1580466872bd4ea3d00f9dc6b3e9bcd58b
5
5
  SHA512:
6
- metadata.gz: 9c09af5a07de3a82ca149d8a30e610c430b8a524099a944e36b67177ce8ac8616207cb5897f57602532b358d9b501fe6544226d6a5b92ef7b425bb816c5bdf3a
7
- data.tar.gz: d3c6f089ead8560e81e5c53cd9d25c89d50da538430642424fcde1620f38fb9551b1aebc8147357d02dee5422e47d13ade0626faea66cfa653f6f5dfba56fbdd
6
+ metadata.gz: 4be0b0dbe5043faa82ee40e2cb32e2651933fe8acb5c869b68e32161d4b50115d00c6a77df53d941b0fce05eb7eab386fb1ba6b69fe13ce9604d477d3eba2ca7
7
+ data.tar.gz: 48999559392d5e3ce0565515453866d3eeb12cc283eba0e0fbb6e6dc8f2d63b9bb9eb202559df357ac4f19ca98a29e050ec102a561af9275b2d57cc358312cd3
data/.travis.yml CHANGED
@@ -1,21 +1,22 @@
1
1
  language: ruby
2
- sudo: false
3
- dist: trusty
2
+ dist: xenial
4
3
  cache: bundler
5
4
 
6
- before_script:
7
- - gem update --system
8
- - gem install bundler
9
-
10
- rvm:
11
- - 2.3
12
- - 2.4
13
- - 2.5
14
- - jruby-head
15
- - ruby-head
16
- - rbx-3
17
5
  matrix:
6
+ include:
7
+ - rvm: 2.3
8
+ - rvm: 2.4
9
+ - rvm: 2.5
10
+ - rvm: 2.6
11
+ - rvm: 2.6
12
+ os: osx
13
+ - rvm: 2.6
14
+ env: COVERAGE=BriefSummary,Coveralls
15
+ - rvm: truffleruby
16
+ - rvm: jruby-head
17
+ env: JRUBY_OPTS="--debug -X+O"
18
+ - rvm: ruby-head
18
19
  allow_failures:
20
+ - rvm: truffleruby
19
21
  - rvm: ruby-head
20
22
  - rvm: jruby-head
21
- - rvm: rbx-3
data/README.md CHANGED
@@ -25,12 +25,16 @@ Or install it yourself as:
25
25
  ## Usage
26
26
 
27
27
  ```ruby
28
- container = Async::Container.new(concurrency: 8) do
29
- # 8 reactors will be spawned, probably in threads since it's the default policy.
28
+ container = Async::Container::Threaded.new
29
+
30
+ container.run(count: 8)
31
+ # 8 reactors will be spawned, in separate threads.
30
32
  Server.new.run(...)
31
33
  end
32
34
 
33
- container = Async::Container::Forked.new(concurrency: 8) do
35
+ container = Async::Container::Forked.new
36
+
37
+ container.run(count: 8) do
34
38
  # 8 reactors will be spawned, in separate forked processes.
35
39
  Server.new.run(...)
36
40
  end
data/Rakefile CHANGED
@@ -4,7 +4,3 @@ require "rspec/core/rake_task"
4
4
  RSpec::Core::RakeTask.new(:test)
5
5
 
6
6
  task :default => :test
7
-
8
- task :coverage do
9
- ENV['COVERAGE'] = 'y'
10
- end
@@ -20,12 +20,15 @@ Gem::Specification.new do |spec|
20
20
 
21
21
  spec.required_ruby_version = "~> 2.0"
22
22
 
23
+ spec.add_runtime_dependency "process-group"
24
+
23
25
  spec.add_runtime_dependency "async", "~> 1.0"
24
26
  spec.add_runtime_dependency "async-io", "~> 1.4"
25
27
 
26
28
  spec.add_development_dependency "async-rspec", "~> 1.1"
27
29
 
28
- spec.add_development_dependency "bundler", "~> 1.3"
30
+ spec.add_development_dependency "covered"
31
+ spec.add_development_dependency "bundler"
29
32
  spec.add_development_dependency "rspec", "~> 3.6"
30
33
  spec.add_development_dependency "rake"
31
34
  end
@@ -0,0 +1,21 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'async/container/forked'
4
+
5
+ container = Async::Container::Forked.new
6
+
7
+ puts "Controller process: #{Process.pid}"
8
+
9
+ container.run(processes: 8, restart: true) do
10
+ puts "Starting process: #{Process.pid}"
11
+
12
+ while true
13
+ sleep 1
14
+ end
15
+ ensure
16
+ puts "Exiting: #{$!}"
17
+ end
18
+
19
+ container.wait
20
+
21
+ puts "Controller procss exiting!"
@@ -18,18 +18,20 @@
18
18
  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
19
  # THE SOFTWARE.
20
20
 
21
+ require_relative 'container/forked'
21
22
  require_relative 'container/threaded'
23
+ require_relative 'container/hybrid'
22
24
 
23
25
  require 'etc'
24
26
 
25
27
  module Async
26
- # Manages a reactor within one or more threads.
28
+ # Containers execute one or more "instances" which typically contain a reactor. A container spawns "instances" using threads and/or processes. Because these are resources that must be cleaned up some how (either by `join` or `waitpid`), their creation is deferred until the user invokes `Container#wait`. When executed this way, the container guarantees that all "instances" will be complete once `Container#wait` returns. Containers are constructs for achieving parallelism, and are not designed to be used directly for concurrency. Typically, you'd create one or more container, add some tasks to it, and then wait for it to complete.
27
29
  module Container
28
- def self.new(**options, &block)
29
- Threaded.new(**options, &block)
30
+ def self.run(concurrency_class: Threaded, **options, &block)
31
+ concurrency_class.run(**options, &block)
30
32
  end
31
33
 
32
- def self.hardware_concurrency
34
+ def self.processor_count
33
35
  Etc.nprocessors
34
36
  rescue
35
37
  2
@@ -19,58 +19,100 @@
19
19
  # THE SOFTWARE.
20
20
 
21
21
  require 'async/reactor'
22
-
23
- require 'async/io/notification'
22
+ require 'process/group'
23
+ require_relative 'statistics'
24
24
 
25
25
  module Async
26
26
  # Manages a reactor within one or more threads.
27
27
  module Container
28
28
  class Forked
29
+ UNNAMED = "Unnamed"
30
+
29
31
  class Instance
30
- def initialize
31
- end
32
-
33
32
  def name= value
34
33
  ::Process.setproctitle(value)
35
34
  end
36
35
  end
37
36
 
38
- def initialize(concurrency: 1, name: nil, &block)
39
- @pids = concurrency.times.collect do
40
- fork do
41
- ::Process.setproctitle(name) if name
37
+ def self.run(*args, &block)
38
+ self.new.run(*args, &block)
39
+ end
40
+
41
+ def initialize
42
+ @group = ::Process::Group.new
43
+ @statistics = Statistics.new
44
+
45
+ @running = true
46
+ end
47
+
48
+ attr :statistics
49
+
50
+ def run(count: Container.processor_count, **options, &block)
51
+ count.times do
52
+ async(**options, &block)
53
+ end
54
+
55
+ return self
56
+ end
57
+
58
+ def spawn(name: nil, restart: false)
59
+ Fiber.new do
60
+ while @running
61
+ @statistics.spawn!
62
+ exit_status = @group.fork do
63
+ ::Process.setproctitle(name) if name
64
+
65
+ yield Instance.new
66
+ end
67
+
68
+ if exit_status.success?
69
+ Async.logger.info(self) {"#{name || UNNAMED} #{exit_status}"}
70
+ else
71
+ @statistics.failure!
72
+ Async.logger.error(self) {exit_status}
73
+ end
42
74
 
43
- begin
44
- Async::Reactor.run(Instance.new, &block)
45
- rescue Interrupt
46
- # Exit cleanly.
75
+ if restart
76
+ @statistics.restart!
77
+ else
78
+ break
47
79
  end
48
80
  end
49
- end
81
+ end.resume
50
82
 
51
- @finished = false
83
+ return self
84
+ end
85
+
86
+ def async(**options, &block)
87
+ spawn(**options) do |instance|
88
+ begin
89
+ Async::Reactor.run(instance, &block)
90
+ rescue Interrupt
91
+ # Graceful exit.
92
+ end
93
+ end
52
94
  end
53
95
 
54
96
  def self.multiprocess?
55
97
  true
56
98
  end
57
99
 
58
- def wait
59
- return if @finished
60
-
61
- @pids.each do |pid|
62
- ::Process.wait(pid)
63
- end
64
-
65
- @finished = true
100
+ def wait(&block)
101
+ @group.wait(&block)
102
+ rescue Interrupt
103
+ # Graceful exit.
104
+ Async.logger.debug(self) {$!}
66
105
  end
67
106
 
68
- def stop(signal = :TERM)
69
- @pids.each do |pid|
70
- ::Process.kill(signal, pid) rescue nil
71
- end
107
+ # Gracefully shut down all children processes.
108
+ def stop(graceful = true, &block)
109
+ @running = false
110
+
111
+ @group.kill(graceful ? :INT : :TERM)
72
112
 
73
- wait
113
+ self.wait(&block)
114
+ ensure
115
+ @running = true
74
116
  end
75
117
  end
76
118
  end
@@ -0,0 +1,48 @@
1
+ # Copyright, 2019, by Samuel G. D. Williams. <http://www.codeotaku.com>
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ # of this software and associated documentation files (the "Software"), to deal
5
+ # in the Software without restriction, including without limitation the rights
6
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ # copies of the Software, and to permit persons to whom the Software is
8
+ # furnished to do so, subject to the following conditions:
9
+ #
10
+ # The above copyright notice and this permission notice shall be included in
11
+ # all copies or substantial portions of the Software.
12
+ #
13
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ # THE SOFTWARE.
20
+
21
+ require_relative 'forked'
22
+ require_relative 'threaded'
23
+
24
+ module Async
25
+ # Manages a reactor within one or more threads.
26
+ module Container
27
+ class Hybrid < Forked
28
+ def run(count: nil, forks: nil, threads: nil, **options, &block)
29
+ processor_count = Container.processor_count
30
+ count ||= processor_count ** 2
31
+ forks ||= [processor_count, count].min
32
+ threads = (count / forks).ceil
33
+
34
+ forks.times do
35
+ self.spawn(**options) do
36
+ container = Threaded.new
37
+
38
+ container.run(count: threads, **options, &block)
39
+
40
+ container.wait
41
+ end
42
+ end
43
+
44
+ return self
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,49 @@
1
+ # Copyright, 2019, by Samuel G. D. Williams. <http://www.codeotaku.com>
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ # of this software and associated documentation files (the "Software"), to deal
5
+ # in the Software without restriction, including without limitation the rights
6
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ # copies of the Software, and to permit persons to whom the Software is
8
+ # furnished to do so, subject to the following conditions:
9
+ #
10
+ # The above copyright notice and this permission notice shall be included in
11
+ # all copies or substantial portions of the Software.
12
+ #
13
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ # THE SOFTWARE.
20
+
21
+ require 'async/reactor'
22
+
23
+ module Async
24
+ module Container
25
+ class Statistics
26
+ def initialize
27
+ @spawns = 0
28
+ @restarts = 0
29
+ @failures = 0
30
+ end
31
+
32
+ attr :spawns
33
+ attr :restarts
34
+ attr :failures
35
+
36
+ def spawn!
37
+ @spawns += 1
38
+ end
39
+
40
+ def restart!
41
+ @restarts += 1
42
+ end
43
+
44
+ def failure!
45
+ @failures += 1
46
+ end
47
+ end
48
+ end
49
+ end
@@ -20,8 +20,7 @@
20
20
 
21
21
  require 'async/reactor'
22
22
  require 'thread'
23
-
24
- require 'async/io/notification'
23
+ require_relative 'statistics'
25
24
 
26
25
  module Async
27
26
  module Container
@@ -37,27 +36,69 @@ module Async
37
36
  end
38
37
  end
39
38
 
40
- def initialize(concurrency: 1, name: nil, &block)
41
- @reactors = concurrency.times.collect do
42
- Async::Reactor.new
39
+ def self.run(*args, &block)
40
+ self.new.run(*args, &block)
41
+ end
42
+
43
+ def initialize
44
+ @threads = []
45
+ @running = true
46
+ @statistics = Statistics.new
47
+ end
48
+
49
+ attr :statistics
50
+
51
+ def run(count: Container.processor_count, **options, &block)
52
+ count.times do
53
+ async(**options, &block)
43
54
  end
44
55
 
45
- @threads = @reactors.collect do |reactor|
46
- ::Thread.new do
47
- thread = ::Thread.current
48
-
49
- thread.abort_on_exception = true
50
- thread.name = name if name
51
-
56
+ return self
57
+ end
58
+
59
+ def spawn(name: nil, restart: false, &block)
60
+ @statistics.spawn!
61
+
62
+ thread = ::Thread.new do
63
+ thread = ::Thread.current
64
+
65
+ thread.report_on_exception = false
66
+ thread.name = name if name
67
+
68
+ instance = Instance.new(thread)
69
+
70
+ while @running
52
71
  begin
53
- reactor.run(Instance.new(thread), &block)
54
- rescue Interrupt
55
- # Exit cleanly.
72
+ yield instance
73
+ rescue Exception => exception
74
+ Async.logger.error(self) {exception}
75
+
76
+ @statistics.failure!
77
+ end
78
+
79
+ if restart
80
+ @statistics.restart!
81
+ else
82
+ break
56
83
  end
57
84
  end
58
85
  end
59
86
 
60
- @finished = nil
87
+ @threads << thread
88
+
89
+ return self
90
+ end
91
+
92
+ def async(name: nil, restart: false, &block)
93
+ spawn do |instance|
94
+ begin
95
+ Async::Reactor.run(instance, &block)
96
+ rescue Interrupt
97
+ # Graceful exit.
98
+ end
99
+ end
100
+
101
+ return self
61
102
  end
62
103
 
63
104
  def self.multiprocess?
@@ -65,17 +106,30 @@ module Async
65
106
  end
66
107
 
67
108
  def wait
68
- return if @finished
109
+ yield if block_given?
69
110
 
70
111
  @threads.each(&:join)
71
-
72
- @finished = true
112
+ @threads.clear
113
+
114
+ return nil
115
+ rescue Interrupt
116
+ # Graceful exit.
117
+ Async.logger.debug(self) {$!}
73
118
  end
74
119
 
75
- def stop
76
- @reactors.each(&:stop)
120
+ # Gracefully shut down all reactors.
121
+ def stop(graceful = true, &block)
122
+ @running = false
123
+
124
+ if graceful
125
+ @threads.each{|thread| thread.raise(Interrupt)}
126
+ else
127
+ @threads.each(&:kill)
128
+ end
77
129
 
78
- wait
130
+ self.wait(&block)
131
+ ensure
132
+ @running = true
79
133
  end
80
134
  end
81
135
  end
@@ -20,6 +20,6 @@
20
20
 
21
21
  module Async
22
22
  module Container
23
- VERSION = "0.9.0"
23
+ VERSION = "0.10.0"
24
24
  end
25
25
  end
@@ -25,13 +25,13 @@ RSpec.describe Async::Container::Controller do
25
25
  mutex = Mutex.new
26
26
  count = 0
27
27
 
28
- subject << Async::Container::Threaded.new(concurrency: 2) do
28
+ subject << Async::Container::Threaded.run(count: 2) do
29
29
  mutex.synchronize do
30
30
  count += 1
31
31
  end
32
32
  end
33
33
 
34
- subject << Async::Container::Threaded.new(concurrency: 2) do
34
+ subject << Async::Container::Threaded.run(count: 2) do
35
35
  mutex.synchronize do
36
36
  count += 1
37
37
  end
@@ -20,18 +20,47 @@
20
20
 
21
21
  require "async/container/forked"
22
22
 
23
+ require_relative 'shared_examples'
24
+
23
25
  RSpec.describe Async::Container::Forked do
26
+ it_behaves_like Async::Container
27
+
24
28
  it "can run concurrently" do
25
- container = described_class.new(name: "Sleepy Jerry") do |task, instance|
29
+ subject.async(name: "Sleepy Jerry") do |task, instance|
26
30
  3.times do |i|
27
31
  puts "Counting Sheep #{i}"
28
32
  instance.name = "Counting Sheep #{i}"
29
33
 
30
- sleep 2
34
+ # sleep 2
31
35
  end
32
36
  end
33
37
 
34
- container.wait
38
+ subject.wait
39
+ end
40
+
41
+ it "can restart child" do
42
+ trigger = IO.pipe
43
+ pids = IO.pipe
44
+
45
+ thread = Thread.new do
46
+ subject.async(restart: true) do
47
+ trigger.first.gets
48
+ pids.last.puts Process.pid.to_s
49
+ end
50
+
51
+ subject.wait
52
+ end
53
+
54
+ 3.times do
55
+ trigger.last.puts "die"
56
+ child_pid = pids.first.gets
57
+ end
58
+
59
+ thread.kill
60
+ thread.join
61
+
62
+ expect(subject.statistics.spawns).to be == 3
63
+ expect(subject.statistics.restarts).to be == 2
35
64
  end
36
65
 
37
66
  it "should be multiprocess" do
@@ -0,0 +1,44 @@
1
+ # Copyright, 2019, by Samuel G. D. Williams. <http://www.codeotaku.com>
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ # of this software and associated documentation files (the "Software"), to deal
5
+ # in the Software without restriction, including without limitation the rights
6
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ # copies of the Software, and to permit persons to whom the Software is
8
+ # furnished to do so, subject to the following conditions:
9
+ #
10
+ # The above copyright notice and this permission notice shall be included in
11
+ # all copies or substantial portions of the Software.
12
+ #
13
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ # THE SOFTWARE.
20
+
21
+ require "async/container/hybrid"
22
+
23
+ require_relative 'shared_examples'
24
+
25
+ RSpec.describe Async::Container::Hybrid do
26
+ it_behaves_like Async::Container
27
+
28
+ it "can run concurrently" do
29
+ subject.run(count: 1, name: "Sleepy Jerry") do |task, instance|
30
+ 3.times do |i|
31
+ puts "Counting Sheep #{i}"
32
+ instance.name = "Counting Sheep #{i}"
33
+
34
+ # sleep 2
35
+ end
36
+ end
37
+
38
+ subject.wait
39
+ end
40
+
41
+ it "should be multiprocess" do
42
+ expect(described_class).to be_multiprocess
43
+ end
44
+ end
@@ -0,0 +1,36 @@
1
+ # Copyright, 2018, by Samuel G. D. Williams. <http://www.codeotaku.com>
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ # of this software and associated documentation files (the "Software"), to deal
5
+ # in the Software without restriction, including without limitation the rights
6
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ # copies of the Software, and to permit persons to whom the Software is
8
+ # furnished to do so, subject to the following conditions:
9
+ #
10
+ # The above copyright notice and this permission notice shall be included in
11
+ # all copies or substantial portions of the Software.
12
+ #
13
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ # THE SOFTWARE.
20
+
21
+ require 'async/rspec/reactor'
22
+
23
+ RSpec.shared_examples_for Async::Container do
24
+ it "can run concurrently" do
25
+ input, output = IO.pipe
26
+
27
+ subject.async do
28
+ output.write "Hello World"
29
+ end
30
+
31
+ subject.wait
32
+
33
+ output.close
34
+ expect(input.read).to be == "Hello World"
35
+ end
36
+ end
@@ -20,13 +20,17 @@
20
20
 
21
21
  require "async/container/threaded"
22
22
 
23
+ require_relative 'shared_examples'
24
+
23
25
  RSpec.describe Async::Container::Threaded do
26
+ it_behaves_like Async::Container
27
+
24
28
  it "can run concurrently" do
25
- container = described_class.new(concurrency: 8, name: "Sleepy Jerry") do
29
+ subject.async(name: "Sleepy Jerry") do
26
30
  sleep 1
27
31
  end
28
32
 
29
- container.stop
33
+ subject.stop
30
34
  end
31
35
 
32
36
  it "should not be multiprocess" do
@@ -21,21 +21,7 @@
21
21
  require "async/container"
22
22
 
23
23
  RSpec.describe Async::Container do
24
- include_context Async::RSpec::Reactor
25
-
26
- it "can run concurrently" do
27
- count = 0
28
-
29
- container = described_class.new do
30
- count += 1
31
- end
32
-
33
- container.stop
34
-
35
- expect(count).to be == 1
36
- end
37
-
38
- it "can get hardware concurrency" do
39
- expect(Async::Container.hardware_concurrency).to be >= 1
24
+ it "can get processor count" do
25
+ expect(Async::Container.processor_count).to be >= 1
40
26
  end
41
27
  end
data/spec/spec_helper.rb CHANGED
@@ -1,23 +1,5 @@
1
1
 
2
- if ENV['COVERAGE'] || ENV['TRAVIS']
3
- begin
4
- require 'simplecov'
5
-
6
- SimpleCov.start do
7
- add_filter "/spec/"
8
- end
9
-
10
- if ENV['TRAVIS']
11
- require 'coveralls'
12
- Coveralls.wear!
13
- end
14
- rescue LoadError
15
- warn "Could not load simplecov: #{$!}"
16
- end
17
- end
18
-
19
- require "bundler/setup"
20
- require "async/container"
2
+ require 'covered/rspec'
21
3
 
22
4
  # Shared rspec helpers:
23
5
  require "async/rspec"
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: async-container
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.0
4
+ version: 0.10.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Samuel Williams
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-01-17 00:00:00.000000000 Z
11
+ date: 2019-03-01 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'
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: async
15
29
  requirement: !ruby/object:Gem::Requirement
@@ -52,20 +66,34 @@ dependencies:
52
66
  - - "~>"
53
67
  - !ruby/object:Gem::Version
54
68
  version: '1.1'
69
+ - !ruby/object:Gem::Dependency
70
+ name: covered
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
55
83
  - !ruby/object:Gem::Dependency
56
84
  name: bundler
57
85
  requirement: !ruby/object:Gem::Requirement
58
86
  requirements:
59
- - - "~>"
87
+ - - ">="
60
88
  - !ruby/object:Gem::Version
61
- version: '1.3'
89
+ version: '0'
62
90
  type: :development
63
91
  prerelease: false
64
92
  version_requirements: !ruby/object:Gem::Requirement
65
93
  requirements:
66
- - - "~>"
94
+ - - ">="
67
95
  - !ruby/object:Gem::Version
68
- version: '1.3'
96
+ version: '0'
69
97
  - !ruby/object:Gem::Dependency
70
98
  name: rspec
71
99
  requirement: !ruby/object:Gem::Requirement
@@ -112,13 +140,18 @@ files:
112
140
  - README.md
113
141
  - Rakefile
114
142
  - async-container.gemspec
143
+ - examples/container.rb
115
144
  - lib/async/container.rb
116
145
  - lib/async/container/controller.rb
117
146
  - lib/async/container/forked.rb
147
+ - lib/async/container/hybrid.rb
148
+ - lib/async/container/statistics.rb
118
149
  - lib/async/container/threaded.rb
119
150
  - lib/async/container/version.rb
120
151
  - spec/async/container/controller_spec.rb
121
152
  - spec/async/container/forked_spec.rb
153
+ - spec/async/container/hybrid_spec.rb
154
+ - spec/async/container/shared_examples.rb
122
155
  - spec/async/container/threaded_spec.rb
123
156
  - spec/async/container_spec.rb
124
157
  - spec/spec_helper.rb
@@ -142,13 +175,15 @@ required_rubygems_version: !ruby/object:Gem::Requirement
142
175
  - !ruby/object:Gem::Version
143
176
  version: '0'
144
177
  requirements: []
145
- rubygems_version: 3.0.1
178
+ rubygems_version: 3.0.2
146
179
  signing_key:
147
180
  specification_version: 4
148
181
  summary: Async is an asynchronous I/O framework based on nio4r.
149
182
  test_files:
150
183
  - spec/async/container/controller_spec.rb
151
184
  - spec/async/container/forked_spec.rb
185
+ - spec/async/container/hybrid_spec.rb
186
+ - spec/async/container/shared_examples.rb
152
187
  - spec/async/container/threaded_spec.rb
153
188
  - spec/async/container_spec.rb
154
189
  - spec/spec_helper.rb