sqewer 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,69 @@
1
+ require_relative '../spec_helper'
2
+
3
+ describe Sqewer::SimpleJob do
4
+ it 'raises a clear error for an unknown attribute' do
5
+ example_class = Class.new do
6
+ attr_accessor :foo, :bar
7
+ include Sqewer::SimpleJob
8
+ end
9
+
10
+ expect {
11
+ example_class.new(zoo: 1, bar: 2)
12
+ }.to raise_error(/Unknown attribute \:zoo for/)
13
+ end
14
+
15
+ it 'uses defined accessors to provide decent string representation' do
16
+ example_class = Class.new do
17
+ attr_accessor :foo, :bar
18
+ include Sqewer::SimpleJob
19
+ end
20
+
21
+ job = example_class.new(foo: 1, bar: 2)
22
+ expect(job.inspect).to include('Class')
23
+ expect(job.inspect).to include('{:foo=>1, :bar=>2}')
24
+ end
25
+
26
+ it 'uses inspectable_attributes to limit the scope of .inspect' do
27
+ example_class = Class.new do
28
+ attr_accessor :foo, :bar
29
+ def inspectable_attributes
30
+ [:foo]
31
+ end
32
+ include Sqewer::SimpleJob
33
+ end
34
+
35
+ job = example_class.new(foo: 1, bar: 2)
36
+ expect(job.inspect).to include('Class')
37
+ expect(job.inspect).to include('{:foo=>1}')
38
+ expect(job.inspect).not_to include('bar')
39
+ end
40
+
41
+ it 'provides for a keyword argument constructor and a to_h method' do
42
+ example_class = Class.new do
43
+ attr_accessor :foo, :bar
44
+ include Sqewer::SimpleJob
45
+ end
46
+
47
+ string_repr = example_class.to_s
48
+
49
+ new_instance = example_class.new(foo: 1, bar: 2)
50
+
51
+ expect(new_instance.foo).to eq(1)
52
+ expect(new_instance.bar).to eq(2)
53
+
54
+ hash_repr = new_instance.to_h
55
+ expect(hash_repr).to eq({foo: 1, bar: 2})
56
+ end
57
+
58
+
59
+ it 'raises if arguments are forgotten' do
60
+ example_class = Class.new do
61
+ attr_accessor :foo, :bar
62
+ include Sqewer::SimpleJob
63
+ end
64
+
65
+ expect {
66
+ example_class.new(foo: 1)
67
+ }.to raise_error('Missing job attribute :bar')
68
+ end
69
+ end
@@ -0,0 +1,59 @@
1
+ require_relative '../spec_helper'
2
+
3
+ describe Sqewer::Submitter do
4
+ describe '.default' do
5
+ it 'returns a set up Submitter with the configured Connection and Serializer' do
6
+ expect(ENV).to receive(:fetch).with('SQS_QUEUE_URL').and_return('https://some-queue.aws.com')
7
+
8
+ s = described_class.default
9
+ expect(s.connection).to respond_to(:send_message)
10
+ expect(s.serializer).to respond_to(:serialize)
11
+ end
12
+ end
13
+
14
+ describe '#initialize' do
15
+ it 'creates a Submitter that you can submit jobs through' do
16
+ fake_serializer = double('Some serializer')
17
+ allow(fake_serializer).to receive(:serialize) {|object_to_serialize|
18
+ expect(object_to_serialize).not_to be_nil
19
+ 'serialized-object-data'
20
+ }
21
+
22
+ fake_connection = double('Some SQS connection')
23
+ expect(fake_connection).to receive(:send_message).at_least(5).times.with('serialized-object-data', {})
24
+
25
+ subject = described_class.new(fake_connection, fake_serializer)
26
+ 5.times { subject.submit!(:some_object) }
27
+ end
28
+
29
+ it 'passes the keyword arguments to send_message on the connection' do
30
+ fake_serializer = double('Some serializer')
31
+ allow(fake_serializer).to receive(:serialize) {|object_to_serialize|
32
+ expect(object_to_serialize).not_to be_nil
33
+ 'serialized-object-data'
34
+ }
35
+
36
+ fake_connection = double('Some SQS connection')
37
+ expect(fake_connection).to receive(:send_message).with('serialized-object-data', {delay_seconds: 5})
38
+
39
+ subject = described_class.new(fake_connection, fake_serializer)
40
+ subject.submit!(:some_object, delay_seconds: 5)
41
+ end
42
+
43
+
44
+ # TODO: should use batched sends
45
+ it 'unsplats the array of jobs and sends them one by one' do
46
+ fake_serializer = double('Some serializer')
47
+ expect(fake_serializer).to receive(:serialize).at_least(5).times {|object_to_serialize|
48
+ expect(object_to_serialize).not_to be_nil
49
+ 'serialized-object-data'
50
+ }
51
+
52
+ fake_connection = double('Some SQS connection')
53
+ expect(fake_connection).to receive(:send_message).at_least(5).times.with('serialized-object-data', {})
54
+
55
+ subject = described_class.new(fake_connection, fake_serializer)
56
+ subject.submit!(:one, :two, :three, :four, :five)
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,130 @@
1
+ require_relative '../spec_helper'
2
+
3
+ describe Sqewer::Worker, :sqs => true do
4
+ let(:silent_logger) { Logger.new(StringIO.new('')) }
5
+
6
+ it 'supports .default' do
7
+ default_worker = described_class.default
8
+ expect(default_worker).to respond_to(:start)
9
+ expect(default_worker).to respond_to(:stop)
10
+ end
11
+
12
+ it 'instantiates a Logger to STDERR by default' do
13
+ expect(Logger).to receive(:new).with(STDERR)
14
+ worker = described_class.new
15
+ end
16
+
17
+ it 'can go through the full cycle of initialize, start, stop, start, stop' do
18
+ worker = described_class.new(logger: silent_logger)
19
+ worker.start
20
+ worker.stop
21
+ worker.start
22
+ worker.stop
23
+ end
24
+
25
+ it 'raises a state exception if being stopped without being started' do
26
+ worker = described_class.new
27
+ expect {
28
+ worker.stop
29
+ }.to raise_error(/Cannot change state/)
30
+ end
31
+
32
+ context 'when the job payload cannot be unserialized from JSON due to invalid syntax' do
33
+ it 'is able to cope with an exception when the job class is unknown (one of generic exceptions)' do
34
+ client = Aws::SQS::Client.new
35
+ client.send_message(queue_url: ENV.fetch('SQS_QUEUE_URL'), message_body: '{"foo":')
36
+
37
+ logger_output = ''
38
+ logger_to_string = Logger.new(StringIO.new(logger_output))
39
+
40
+ worker = described_class.new(logger: logger_to_string)
41
+
42
+ worker.start
43
+ sleep 2
44
+ worker.stop
45
+
46
+ expect(logger_output).to include('unexpected token at \'{"foo":')
47
+ expect(logger_output).to include('Stopping (clean shutdown)')
48
+ end
49
+ end
50
+
51
+ context 'when the job cannot be instantiated due to an unknown class' do
52
+ it 'is able to cope with an exception when the job class is unknown (one of generic exceptions)' do
53
+ payload = JSON.dump({job_class: 'UnknownJobClass', arg1: 'some value'})
54
+
55
+ client = Aws::SQS::Client.new
56
+ client.send_message(queue_url: ENV.fetch('SQS_QUEUE_URL'), message_body: payload)
57
+
58
+ logger_output = ''
59
+ logger_to_string = Logger.new(StringIO.new(logger_output))
60
+
61
+ worker = described_class.new(logger: logger_to_string)
62
+
63
+ worker.start
64
+ sleep 2
65
+ worker.stop
66
+
67
+ expect(logger_output).to include('uninitialized constant UnknownJobClass')
68
+ expect(logger_output).to include('Stopping (clean shutdown)')
69
+ end
70
+ end
71
+
72
+ context 'with a job that spawns another job' do
73
+ it 'sets up the processing pipeline so that jobs can execute in sequence' do
74
+ class SecondaryJob
75
+ def run
76
+ File.open('secondary-job-run','w') {}
77
+ end
78
+ end
79
+
80
+ class InitialJob
81
+ def run(executor)
82
+ File.open('initial-job-run','w') {}
83
+ executor.submit!(SecondaryJob.new)
84
+ end
85
+ end
86
+
87
+ payload = JSON.dump({job_class: 'InitialJob'})
88
+ client = Aws::SQS::Client.new
89
+ client.send_message(queue_url: ENV.fetch('SQS_QUEUE_URL'), message_body: payload)
90
+
91
+ logger_output = ''
92
+ logger_to_string = Logger.new(StringIO.new(logger_output))
93
+ worker = described_class.new(logger: logger_to_string, num_threads: 8)
94
+
95
+ worker.start
96
+
97
+ begin
98
+ poll(fail_after: 3) { File.exist?('initial-job-run') }
99
+ poll(fail_after: 3) { File.exist?('secondary-job-run') }
100
+
101
+ File.unlink('initial-job-run')
102
+ File.unlink('secondary-job-run')
103
+ expect(true).to eq(true)
104
+ ensure
105
+ worker.stop
106
+ end
107
+
108
+ # Run with a per-process isolator too
109
+ client = Aws::SQS::Client.new
110
+ client.send_message(queue_url: ENV.fetch('SQS_QUEUE_URL'), message_body: payload)
111
+
112
+ logger_output = ''
113
+ logger_to_string = Logger.new(StringIO.new(logger_output))
114
+ worker = described_class.new(logger: logger_to_string, num_threads: 8, isolator: Sqewer::Isolator.process)
115
+
116
+ worker.start
117
+
118
+ begin
119
+ poll(fail_after: 3) { File.exist?('initial-job-run') }
120
+ poll(fail_after: 3) { File.exist?('secondary-job-run') }
121
+
122
+ File.unlink('initial-job-run')
123
+ File.unlink('secondary-job-run')
124
+ expect(true).to eq(true)
125
+ ensure
126
+ worker.stop
127
+ end
128
+ end
129
+ end
130
+ end
@@ -0,0 +1,108 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+ # stub: sqewer 1.0.0 ruby lib
6
+
7
+ Gem::Specification.new do |s|
8
+ s.name = "sqewer"
9
+ s.version = "1.0.0"
10
+
11
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
12
+ s.require_paths = ["lib"]
13
+ s.authors = ["Julik Tarkhanov"]
14
+ s.date = "2016-01-18"
15
+ s.description = "Process jobs from SQS"
16
+ s.email = "me@julik.nl"
17
+ s.extra_rdoc_files = [
18
+ "README.md"
19
+ ]
20
+ s.files = [
21
+ ".gitlab-ci.yml",
22
+ ".yardopts",
23
+ "DETAILS.md",
24
+ "FAQ.md",
25
+ "Gemfile",
26
+ "README.md",
27
+ "Rakefile",
28
+ "example.env",
29
+ "lib/sqewer.rb",
30
+ "lib/sqewer/atomic_counter.rb",
31
+ "lib/sqewer/cli.rb",
32
+ "lib/sqewer/connection.rb",
33
+ "lib/sqewer/contrib/appsignal_wrapper.rb",
34
+ "lib/sqewer/contrib/performable.rb",
35
+ "lib/sqewer/execution_context.rb",
36
+ "lib/sqewer/isolator.rb",
37
+ "lib/sqewer/middleware_stack.rb",
38
+ "lib/sqewer/null_logger.rb",
39
+ "lib/sqewer/serializer.rb",
40
+ "lib/sqewer/simple_job.rb",
41
+ "lib/sqewer/submitter.rb",
42
+ "lib/sqewer/version.rb",
43
+ "lib/sqewer/worker.rb",
44
+ "spec/conveyor_belt_spec.rb",
45
+ "spec/spec_helper.rb",
46
+ "spec/sqewer/atomic_counter_spec.rb",
47
+ "spec/sqewer/cli_app.rb",
48
+ "spec/sqewer/cli_spec.rb",
49
+ "spec/sqewer/connection_spec.rb",
50
+ "spec/sqewer/execution_context_spec.rb",
51
+ "spec/sqewer/middleware_stack_spec.rb",
52
+ "spec/sqewer/serializer_spec.rb",
53
+ "spec/sqewer/simple_job_spec.rb",
54
+ "spec/sqewer/submitter_spec.rb",
55
+ "spec/sqewer/worker_spec.rb",
56
+ "sqewer.gemspec"
57
+ ]
58
+ s.homepage = "https://gitlab.wetransfer.net/julik/sqewer"
59
+ s.licenses = ["MIT"]
60
+ s.rubygems_version = "2.2.2"
61
+ s.summary = "A full-featured library for all them worker needs"
62
+
63
+ if s.respond_to? :specification_version then
64
+ s.specification_version = 4
65
+
66
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
67
+ s.add_runtime_dependency(%q<aws-sdk>, ["~> 2"])
68
+ s.add_runtime_dependency(%q<very_tiny_state_machine>, ["~> 1"])
69
+ s.add_runtime_dependency(%q<hash_tools>, [">= 0"])
70
+ s.add_runtime_dependency(%q<exceptional_fork>, [">= 0"])
71
+ s.add_development_dependency(%q<ks>, [">= 0"])
72
+ s.add_development_dependency(%q<dotenv>, [">= 0"])
73
+ s.add_development_dependency(%q<rake>, [">= 0"])
74
+ s.add_development_dependency(%q<rspec>, ["~> 3.2.0"])
75
+ s.add_development_dependency(%q<simplecov>, [">= 0"])
76
+ s.add_development_dependency(%q<rdoc>, ["~> 3.12"])
77
+ s.add_development_dependency(%q<bundler>, ["~> 1.0"])
78
+ s.add_development_dependency(%q<jeweler>, ["~> 2.0.1"])
79
+ else
80
+ s.add_dependency(%q<aws-sdk>, ["~> 2"])
81
+ s.add_dependency(%q<very_tiny_state_machine>, ["~> 1"])
82
+ s.add_dependency(%q<hash_tools>, [">= 0"])
83
+ s.add_dependency(%q<exceptional_fork>, [">= 0"])
84
+ s.add_dependency(%q<ks>, [">= 0"])
85
+ s.add_dependency(%q<dotenv>, [">= 0"])
86
+ s.add_dependency(%q<rake>, [">= 0"])
87
+ s.add_dependency(%q<rspec>, ["~> 3.2.0"])
88
+ s.add_dependency(%q<simplecov>, [">= 0"])
89
+ s.add_dependency(%q<rdoc>, ["~> 3.12"])
90
+ s.add_dependency(%q<bundler>, ["~> 1.0"])
91
+ s.add_dependency(%q<jeweler>, ["~> 2.0.1"])
92
+ end
93
+ else
94
+ s.add_dependency(%q<aws-sdk>, ["~> 2"])
95
+ s.add_dependency(%q<very_tiny_state_machine>, ["~> 1"])
96
+ s.add_dependency(%q<hash_tools>, [">= 0"])
97
+ s.add_dependency(%q<exceptional_fork>, [">= 0"])
98
+ s.add_dependency(%q<ks>, [">= 0"])
99
+ s.add_dependency(%q<dotenv>, [">= 0"])
100
+ s.add_dependency(%q<rake>, [">= 0"])
101
+ s.add_dependency(%q<rspec>, ["~> 3.2.0"])
102
+ s.add_dependency(%q<simplecov>, [">= 0"])
103
+ s.add_dependency(%q<rdoc>, ["~> 3.12"])
104
+ s.add_dependency(%q<bundler>, ["~> 1.0"])
105
+ s.add_dependency(%q<jeweler>, ["~> 2.0.1"])
106
+ end
107
+ end
108
+
metadata ADDED
@@ -0,0 +1,248 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: sqewer
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Julik Tarkhanov
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-01-18 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: aws-sdk
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '2'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '2'
27
+ - !ruby/object:Gem::Dependency
28
+ name: very_tiny_state_machine
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1'
41
+ - !ruby/object:Gem::Dependency
42
+ name: hash_tools
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: exceptional_fork
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: ks
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'
83
+ - !ruby/object:Gem::Dependency
84
+ name: dotenv
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: rake
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: rspec
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: 3.2.0
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: 3.2.0
125
+ - !ruby/object:Gem::Dependency
126
+ name: simplecov
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
139
+ - !ruby/object:Gem::Dependency
140
+ name: rdoc
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - "~>"
144
+ - !ruby/object:Gem::Version
145
+ version: '3.12'
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - "~>"
151
+ - !ruby/object:Gem::Version
152
+ version: '3.12'
153
+ - !ruby/object:Gem::Dependency
154
+ name: bundler
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - "~>"
158
+ - !ruby/object:Gem::Version
159
+ version: '1.0'
160
+ type: :development
161
+ prerelease: false
162
+ version_requirements: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - "~>"
165
+ - !ruby/object:Gem::Version
166
+ version: '1.0'
167
+ - !ruby/object:Gem::Dependency
168
+ name: jeweler
169
+ requirement: !ruby/object:Gem::Requirement
170
+ requirements:
171
+ - - "~>"
172
+ - !ruby/object:Gem::Version
173
+ version: 2.0.1
174
+ type: :development
175
+ prerelease: false
176
+ version_requirements: !ruby/object:Gem::Requirement
177
+ requirements:
178
+ - - "~>"
179
+ - !ruby/object:Gem::Version
180
+ version: 2.0.1
181
+ description: Process jobs from SQS
182
+ email: me@julik.nl
183
+ executables: []
184
+ extensions: []
185
+ extra_rdoc_files:
186
+ - README.md
187
+ files:
188
+ - ".gitlab-ci.yml"
189
+ - ".yardopts"
190
+ - DETAILS.md
191
+ - FAQ.md
192
+ - Gemfile
193
+ - README.md
194
+ - Rakefile
195
+ - example.env
196
+ - lib/sqewer.rb
197
+ - lib/sqewer/atomic_counter.rb
198
+ - lib/sqewer/cli.rb
199
+ - lib/sqewer/connection.rb
200
+ - lib/sqewer/contrib/appsignal_wrapper.rb
201
+ - lib/sqewer/contrib/performable.rb
202
+ - lib/sqewer/execution_context.rb
203
+ - lib/sqewer/isolator.rb
204
+ - lib/sqewer/middleware_stack.rb
205
+ - lib/sqewer/null_logger.rb
206
+ - lib/sqewer/serializer.rb
207
+ - lib/sqewer/simple_job.rb
208
+ - lib/sqewer/submitter.rb
209
+ - lib/sqewer/version.rb
210
+ - lib/sqewer/worker.rb
211
+ - spec/conveyor_belt_spec.rb
212
+ - spec/spec_helper.rb
213
+ - spec/sqewer/atomic_counter_spec.rb
214
+ - spec/sqewer/cli_app.rb
215
+ - spec/sqewer/cli_spec.rb
216
+ - spec/sqewer/connection_spec.rb
217
+ - spec/sqewer/execution_context_spec.rb
218
+ - spec/sqewer/middleware_stack_spec.rb
219
+ - spec/sqewer/serializer_spec.rb
220
+ - spec/sqewer/simple_job_spec.rb
221
+ - spec/sqewer/submitter_spec.rb
222
+ - spec/sqewer/worker_spec.rb
223
+ - sqewer.gemspec
224
+ homepage: https://gitlab.wetransfer.net/julik/sqewer
225
+ licenses:
226
+ - MIT
227
+ metadata: {}
228
+ post_install_message:
229
+ rdoc_options: []
230
+ require_paths:
231
+ - lib
232
+ required_ruby_version: !ruby/object:Gem::Requirement
233
+ requirements:
234
+ - - ">="
235
+ - !ruby/object:Gem::Version
236
+ version: '0'
237
+ required_rubygems_version: !ruby/object:Gem::Requirement
238
+ requirements:
239
+ - - ">="
240
+ - !ruby/object:Gem::Version
241
+ version: '0'
242
+ requirements: []
243
+ rubyforge_project:
244
+ rubygems_version: 2.2.2
245
+ signing_key:
246
+ specification_version: 4
247
+ summary: A full-featured library for all them worker needs
248
+ test_files: []