async-worker 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 99178fd374238f9b06532823b7df6379a1910556af9b8b7ffa6bbc31b5908594
4
+ data.tar.gz: 927dd858f3fc051bb31e5dd326ae7f33e7196bd005c639e5700090fb0451aa5f
5
+ SHA512:
6
+ metadata.gz: 1bd42b5ada43a451741f49141764a7bc1838f3107a7e982fea025318bfb14a3fccbea22f01a18d2305e6b013b632ccc7df8b76375bf772143f397af677f77893
7
+ data.tar.gz: 776051b39eb57b26c8e6085419493579d8376c0bcc5f45b80d98eead7fcec06d7efd95465b843fd118977e06795826db3af6dab0e8ee52936c02b974b756fe67
@@ -0,0 +1,11 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+
10
+ # rspec failure tracking
11
+ .rspec_status
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --warnings
3
+ --require spec_helper
@@ -0,0 +1,19 @@
1
+ language: ruby
2
+ sudo: false
3
+ dist: trusty
4
+ cache: bundler
5
+
6
+ matrix:
7
+ include:
8
+ - rvm: 2.2
9
+ - rvm: 2.3
10
+ - rvm: 2.4
11
+ - rvm: 2.5
12
+ - rvm: jruby-head
13
+ env: JRUBY_OPTS="--debug -X+O"
14
+ - rvm: ruby-head
15
+ - rvm: rbx-3
16
+ allow_failures:
17
+ - rvm: ruby-head
18
+ - rvm: jruby-head
19
+ - rvm: rbx-3
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source "https://rubygems.org"
2
+
3
+ git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
4
+
5
+ # Specify your gem's dependencies in async-worker.gemspec
6
+ gemspec
@@ -0,0 +1,49 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ async-worker (0.1.0)
5
+ async (~> 1.0)
6
+ async-io (~> 1.3)
7
+
8
+ GEM
9
+ remote: https://rubygems.org/
10
+ specs:
11
+ async (1.5.0)
12
+ nio4r (~> 2.0)
13
+ timers (~> 4.1)
14
+ async-io (1.7.0)
15
+ async (~> 1.3)
16
+ async-rspec (1.3.1)
17
+ rspec (~> 3.0)
18
+ diff-lcs (1.3)
19
+ hitimes (1.2.6)
20
+ nio4r (2.3.0)
21
+ rake (10.5.0)
22
+ rspec (3.7.0)
23
+ rspec-core (~> 3.7.0)
24
+ rspec-expectations (~> 3.7.0)
25
+ rspec-mocks (~> 3.7.0)
26
+ rspec-core (3.7.1)
27
+ rspec-support (~> 3.7.0)
28
+ rspec-expectations (3.7.0)
29
+ diff-lcs (>= 1.2.0, < 2.0)
30
+ rspec-support (~> 3.7.0)
31
+ rspec-mocks (3.7.0)
32
+ diff-lcs (>= 1.2.0, < 2.0)
33
+ rspec-support (~> 3.7.0)
34
+ rspec-support (3.7.1)
35
+ timers (4.1.2)
36
+ hitimes
37
+
38
+ PLATFORMS
39
+ ruby
40
+
41
+ DEPENDENCIES
42
+ async-rspec (~> 1.0)
43
+ async-worker!
44
+ bundler (~> 1.16)
45
+ rake (~> 10.0)
46
+ rspec (~> 3.0)
47
+
48
+ BUNDLED WITH
49
+ 1.16.1
@@ -0,0 +1,81 @@
1
+ # Async::Worker
2
+
3
+ Provides a thread-pool backed work queue for executing blocking operations in a non-blocking fashion using [async].
4
+
5
+ [async]: https://github.com/socketry/async
6
+
7
+ [![Build Status](https://secure.travis-ci.org/socketry/async-worker.svg)](http://travis-ci.org/socketry/async-worker)
8
+ [![Code Climate](https://codeclimate.com/github/socketry/async-worker.svg)](https://codeclimate.com/github/socketry/async-worker)
9
+ [![Coverage Status](https://coveralls.io/repos/socketry/async-worker/badge.svg)](https://coveralls.io/r/socketry/async-worker)
10
+
11
+ ## Installation
12
+
13
+ Add this line to your application's Gemfile:
14
+
15
+ ```ruby
16
+ gem 'async-worker'
17
+ ```
18
+
19
+ And then execute:
20
+
21
+ $ bundle
22
+
23
+ Or install it yourself as:
24
+
25
+ $ gem install async-worker
26
+
27
+ ## Usage
28
+
29
+ Create a pool and execute jobs using it:
30
+
31
+ ```ruby
32
+ Async::Reactor.run do |task|
33
+ # Make a pool with two workers:
34
+ pool = Async::Worker::Pool.new(2)
35
+
36
+ tasks = 5.times.collect do
37
+ task.async do
38
+ # Add the work to the queue and wait for it to complete:
39
+ pool.async do
40
+ sleep 0.1
41
+ end
42
+ end
43
+ end
44
+
45
+ tasks.each(&:wait)
46
+
47
+ pool.close
48
+ end
49
+ ```
50
+
51
+ ## Contributing
52
+
53
+ 1. Fork it
54
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
55
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
56
+ 4. Push to the branch (`git push origin my-new-feature`)
57
+ 5. Create new Pull Request
58
+
59
+ ## License
60
+
61
+ Released under the MIT license.
62
+
63
+ Copyright, 2017, by [Samuel G. D. Williams](http://www.codeotaku.com/samuel-williams).
64
+
65
+ Permission is hereby granted, free of charge, to any person obtaining a copy
66
+ of this software and associated documentation files (the "Software"), to deal
67
+ in the Software without restriction, including without limitation the rights
68
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
69
+ copies of the Software, and to permit persons to whom the Software is
70
+ furnished to do so, subject to the following conditions:
71
+
72
+ The above copyright notice and this permission notice shall be included in
73
+ all copies or substantial portions of the Software.
74
+
75
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
76
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
77
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
78
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
79
+ LIABILITY, WHETHER IN AN ACTWorkerN OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
80
+ OUT OF OR IN CONNECTWorkerN WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
81
+ THE SOFTWARE.
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:test)
5
+
6
+ task :default => :test
@@ -0,0 +1,27 @@
1
+
2
+ require_relative "lib/async/worker/version"
3
+
4
+ Gem::Specification.new do |spec|
5
+ spec.name = "async-worker"
6
+ spec.version = Async::Worker::VERSION
7
+ spec.authors = ["Samuel Williams"]
8
+ spec.email = ["samuel.williams@oriontransfer.co.nz"]
9
+
10
+ spec.summary = "Non-blocking thread-pool based workers for blocking operations."
11
+ spec.homepage = "https://github.com/socketry/async-worker"
12
+
13
+ spec.files = `git ls-files`.split($/)
14
+ spec.executables = spec.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
15
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
16
+ spec.require_paths = ["lib"]
17
+ spec.has_rdoc = "yard"
18
+
19
+ spec.add_dependency 'async', '~> 1.0'
20
+ spec.add_dependency 'async-io', '~> 1.3'
21
+
22
+ spec.add_development_dependency "async-rspec", "~> 1.0"
23
+
24
+ spec.add_development_dependency "bundler", "~> 1.16"
25
+ spec.add_development_dependency "rake", "~> 10.0"
26
+ spec.add_development_dependency "rspec", "~> 3.0"
27
+ end
data/bug.rb ADDED
@@ -0,0 +1,27 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'thread'
4
+
5
+ puts RUBY_VERSION
6
+
7
+ 100.times.collect do
8
+ Thread.new do
9
+ mutex = Mutex.new
10
+ input, output = IO.pipe
11
+
12
+ worker = Thread.new do
13
+ sleep(0.1)
14
+ # mutex.synchronize do
15
+ output.syswrite('.')
16
+ # end
17
+ end
18
+
19
+ input.read(1)
20
+
21
+ # mutex.synchronize do
22
+ input.close
23
+ output.close
24
+ # end
25
+ worker.join
26
+ end
27
+ end.each(&:join)
@@ -0,0 +1,22 @@
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_relative 'worker/version'
22
+ require_relative 'worker/pool'
@@ -0,0 +1,61 @@
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/io/generic'
22
+
23
+ require 'thread'
24
+
25
+ module Async
26
+ module Worker
27
+ # A cross-thread notification pipe.
28
+ class Notification
29
+ def initialize
30
+ pipe = ::IO.pipe
31
+
32
+ @mutex = Mutex.new
33
+ @input = pipe.first
34
+ @output = pipe.last
35
+ end
36
+
37
+ def close
38
+ # Due to bugs in MRI, we need to synchronize this.
39
+ @mutex.synchronize do
40
+ @input.close
41
+ @output.close
42
+ end
43
+ end
44
+
45
+ # Wait for signal to be called.
46
+ # @return [Object]
47
+ def wait
48
+ wrapper = Async::IO::Generic.new(@input)
49
+ wrapper.read(1)
50
+ end
51
+
52
+ # Signal to a given task that it should resume operations.
53
+ # @return [void]
54
+ def signal
55
+ @mutex.synchronize do
56
+ @output.syswrite(".")
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,78 @@
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/reactor'
22
+ require 'thread'
23
+
24
+ require_relative 'notification'
25
+
26
+ module Async
27
+ module Worker
28
+ class Pool
29
+ def initialize(workers = 4)
30
+ @threads = []
31
+
32
+ @queue = Thread::Queue.new
33
+
34
+ workers.times {create_worker}
35
+ end
36
+
37
+ def close
38
+ @queue.close
39
+ @threads.each(&:join)
40
+ end
41
+
42
+ def async(&block)
43
+ notification = Notification.new
44
+
45
+ result = nil
46
+
47
+ job = lambda do
48
+ begin
49
+ result = block.call
50
+ rescue Exception
51
+ result = $!
52
+ ensure
53
+ notification.signal
54
+ end
55
+ end
56
+
57
+ @queue << job
58
+
59
+ notification.wait
60
+ notification.close
61
+
62
+ return result
63
+ end
64
+
65
+ private
66
+
67
+ def create_worker
68
+ thread = Thread.new do
69
+ while job = @queue.pop
70
+ job.call
71
+ end
72
+ end
73
+
74
+ @threads << thread
75
+ end
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,25 @@
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
+ module Async
22
+ module Worker
23
+ VERSION = "0.1.0"
24
+ end
25
+ end
@@ -0,0 +1,30 @@
1
+
2
+ require 'benchmark'
3
+
4
+ RSpec.describe Async::Worker do
5
+ include_context Async::RSpec::Reactor
6
+
7
+ let(:count) {20}
8
+
9
+ it "can execute work in parallel" do
10
+ task = Async::Task.current
11
+ pool = Async::Worker::Pool.new(count)
12
+
13
+ tasks = []
14
+
15
+ duration = Benchmark.realtime do
16
+ count.times do
17
+ tasks << task.async do
18
+ pool.async do
19
+ sleep 0.1
20
+ end
21
+ end
22
+ end
23
+
24
+ tasks.each(&:wait)
25
+ end
26
+
27
+ expect(duration).to be_within(0.01).of(0.1)
28
+ pool.close
29
+ end
30
+ end
@@ -0,0 +1,32 @@
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/worker"
21
+
22
+ # Shared rspec helpers:
23
+ require "async/rspec"
24
+
25
+ RSpec.configure do |config|
26
+ # Enable flags like --only-failures and --next-failure
27
+ config.example_status_persistence_file_path = ".rspec_status"
28
+
29
+ config.expect_with :rspec do |c|
30
+ c.syntax = :expect
31
+ end
32
+ end
metadata ADDED
@@ -0,0 +1,144 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: async-worker
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Samuel Williams
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2018-04-12 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: async
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: async-io
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.3'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.3'
41
+ - !ruby/object:Gem::Dependency
42
+ name: async-rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '1.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: bundler
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '1.16'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '1.16'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rake
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '10.0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '10.0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rspec
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '3.0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '3.0'
97
+ description:
98
+ email:
99
+ - samuel.williams@oriontransfer.co.nz
100
+ executables: []
101
+ extensions: []
102
+ extra_rdoc_files: []
103
+ files:
104
+ - ".gitignore"
105
+ - ".rspec"
106
+ - ".travis.yml"
107
+ - Gemfile
108
+ - Gemfile.lock
109
+ - README.md
110
+ - Rakefile
111
+ - async-worker.gemspec
112
+ - bug.rb
113
+ - lib/async/worker.rb
114
+ - lib/async/worker/notification.rb
115
+ - lib/async/worker/pool.rb
116
+ - lib/async/worker/version.rb
117
+ - spec/async/worker_spec.rb
118
+ - spec/spec_helper.rb
119
+ homepage: https://github.com/socketry/async-worker
120
+ licenses: []
121
+ metadata: {}
122
+ post_install_message:
123
+ rdoc_options: []
124
+ require_paths:
125
+ - lib
126
+ required_ruby_version: !ruby/object:Gem::Requirement
127
+ requirements:
128
+ - - ">="
129
+ - !ruby/object:Gem::Version
130
+ version: '0'
131
+ required_rubygems_version: !ruby/object:Gem::Requirement
132
+ requirements:
133
+ - - ">="
134
+ - !ruby/object:Gem::Version
135
+ version: '0'
136
+ requirements: []
137
+ rubyforge_project:
138
+ rubygems_version: 2.7.6
139
+ signing_key:
140
+ specification_version: 4
141
+ summary: Non-blocking thread-pool based workers for blocking operations.
142
+ test_files:
143
+ - spec/async/worker_spec.rb
144
+ - spec/spec_helper.rb