sidejob 3.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,108 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'SideJob testing helpers' do
4
+ class TestLongRunning
5
+ include SideJob::Worker
6
+ register
7
+ def perform
8
+ sleep 3
9
+ end
10
+ end
11
+
12
+ class TestFailure
13
+ include SideJob::Worker
14
+ register
15
+ def perform
16
+ raise 'bad error'
17
+ end
18
+ end
19
+
20
+ class TestMysteriousFailure
21
+ include SideJob::Worker
22
+ register
23
+ def perform
24
+ self.status = 'failed'
25
+ end
26
+ end
27
+
28
+ describe 'SideJob::Worker.drain_queue' do
29
+ it 'runs jobs' do
30
+ job = SideJob.queue('testq', 'TestSum')
31
+ 5.times {|i| job.input(:in).write i}
32
+ job.input(:ready).write 1
33
+ job2 = SideJob.queue('testq', 'TestSum')
34
+ 6.times {|i| job2.input(:in).write i}
35
+ job2.input(:ready).write 1
36
+ expect(job.output(:sum).data?).to be false
37
+ expect(job2.output(:sum).data?).to be false
38
+ SideJob::Worker.drain_queue
39
+ expect(job.output(:sum).read).to eq 10
40
+ expect(job2.output(:sum).read).to eq 15
41
+ end
42
+
43
+ it 'can specify a timeout' do
44
+ job = SideJob.queue('testq', 'TestLongRunning')
45
+ expect { SideJob::Worker.drain_queue(timeout: 0.25) }.to raise_error(Timeout::Error)
46
+ end
47
+
48
+ it 'raises errors by default' do
49
+ job = SideJob.queue('testq', 'TestFailure')
50
+ expect { SideJob::Worker.drain_queue }.to raise_error(RuntimeError, 'bad error')
51
+ end
52
+
53
+ it 'raises error if worker mysteriously fails' do
54
+ job = SideJob.queue('testq', 'TestMysteriousFailure')
55
+ expect { SideJob::Worker.drain_queue }.to raise_error(RuntimeError)
56
+ end
57
+
58
+ it 'can disable raising of errors' do
59
+ job = SideJob.queue('testq', 'TestFailure')
60
+ expect { SideJob::Worker.drain_queue(errors: false) }.not_to raise_error
61
+ end
62
+ end
63
+
64
+ describe 'SideJob::Job#run_inline' do
65
+ it 'runs a single job once' do
66
+ job = SideJob.queue('testq', 'TestSum')
67
+ 5.times {|i| job.input(:in).write i}
68
+ job.input(:ready).write 1
69
+ expect(job.output(:sum).data?).to be false
70
+ job.run_inline
71
+ expect(job.status).to eq 'completed'
72
+ expect(job.output(:sum).read).to eq 10
73
+ end
74
+
75
+ it 'queues a non-queued job by default' do
76
+ job = SideJob.queue('testq', 'TestSum')
77
+ 5.times {|i| job.input(:in).write i}
78
+ job.input(:ready).write 1
79
+ job.status = 'suspended'
80
+ job.run_inline
81
+ expect(job.output(:sum).read).to eq 10
82
+ end
83
+
84
+ it 'can turn off queuing of a job' do
85
+ job = SideJob.queue('testq', 'TestSum')
86
+ 5.times {|i| job.input(:in).write i}
87
+ job.input(:ready).write 1
88
+ job.status = 'suspended'
89
+ job.run_inline queue: false
90
+ expect(job.output(:sum).data?).to be false
91
+ end
92
+
93
+ it 'raises errors by default' do
94
+ job = SideJob.queue('testq', 'TestFailure')
95
+ expect { job.run_inline }.to raise_error(RuntimeError, 'bad error')
96
+ end
97
+
98
+ it 'raises error if worker mysteriously fails' do
99
+ job = SideJob.queue('testq', 'TestMysteriousFailure')
100
+ expect { job.run_inline }.to raise_error(RuntimeError)
101
+ end
102
+
103
+ it 'can disable raising of errors' do
104
+ job = SideJob.queue('testq', 'TestFailure')
105
+ expect { job.run_inline(errors: false) }.not_to raise_error
106
+ end
107
+ end
108
+ end
@@ -0,0 +1,201 @@
1
+ require 'spec_helper'
2
+
3
+ describe SideJob::Worker do
4
+ before do
5
+ @job = SideJob.queue('testq', 'TestWorker', inports: {
6
+ in1: {},
7
+ in2: {},
8
+ memory: { mode: :memory },
9
+ default: { default: 'default' },
10
+ default_null: { default: nil },
11
+ }, outports: {out1: {}})
12
+ @worker = TestWorker.new
13
+ @worker.jid = @job.id
14
+ @worker.status = 'running'
15
+ end
16
+
17
+ describe '.register_all' do
18
+ it 'overwrites existing data with current registry' do
19
+ spec = {abc: [1, 2]}
20
+ SideJob.redis.hmset 'workers:q1', 'foo', 'bar'
21
+ SideJob::Worker.register_all('q1')
22
+ expect(SideJob.redis.hget('workers:q1', 'foo')).to be nil
23
+ end
24
+ end
25
+
26
+ describe '.config' do
27
+ it 'returns nil for a non-existing worker' do
28
+ expect(SideJob::Worker.config('noq', 'NoWorker')).to be nil
29
+ end
30
+
31
+ it 'returns a worker config that has been registered for the current queue' do
32
+ expect(SideJob::Worker.config('testq', 'TestWorker')).to eq JSON.parse(SideJob::Worker.registry['TestWorker'].to_json)
33
+ end
34
+
35
+ it 'returns a worker config that has been registered elsewhere' do
36
+ config = {'abc' => [1, 2]}
37
+ SideJob.redis.hmset 'workers:q1', 'NewWorker', config.to_json
38
+ expect(SideJob::Worker.config('q1', 'NewWorker')).to eq config
39
+ end
40
+ end
41
+
42
+ describe '.register' do
43
+ class TestWorkerRegister
44
+ include SideJob::Worker
45
+ register(
46
+ my_register_key: [1, 2, 3]
47
+ )
48
+ def perform
49
+ end
50
+ end
51
+
52
+ it 'registers a worker configuration' do
53
+ expect(SideJob::Worker.registry['TestWorkerRegister']).to eq({my_register_key: [1,2,3]})
54
+ end
55
+ end
56
+
57
+ it 'includes SideJob::JobMethods' do
58
+ expect(TestWorker.included_modules).to include(SideJob::JobMethods)
59
+ end
60
+
61
+ it '#suspend raises exception' do
62
+ expect { @worker.suspend }.to raise_error(SideJob::Worker::Suspended)
63
+ end
64
+
65
+ describe '#queue' do
66
+ it 'can queue child jobs' do
67
+ expect(SideJob).to receive(:queue).with('testq', 'TestWorker', args: [1,2], inports: {'myport' => {'mode' => 'memory'}}, parent: @job, name: 'child', by: "job:#{@worker.id}").and_call_original
68
+ expect {
69
+ child = @worker.queue('testq', 'TestWorker', args: [1,2], inports: {'myport' => {'mode' => 'memory'}}, name: 'child')
70
+ expect(child.parent).to eq(@job)
71
+ expect(@job.children).to eq('child' => child)
72
+ }.to change {Sidekiq::Stats.new.enqueued}.by(1)
73
+ end
74
+
75
+ it 'queues with by string set to self' do
76
+ child = @worker.queue('testq', 'TestWorker', name: 'child')
77
+ expect(child.get(:created_by)).to eq "job:#{@worker.id}"
78
+ end
79
+
80
+ it 'groups initial port data' do
81
+ now = Time.now
82
+ allow(Time).to receive(:now) { now }
83
+ child = @worker.queue('testq', 'TestWorker', name: 'child', inports: {'inport1' => {data: [1,2]}}, outports: {'outport1' => {data: [3,4]}})
84
+ expect(SideJob.logs).to eq [{'timestamp' => SideJob.timestamp, 'job' => @worker.id,
85
+ 'read' => [],
86
+ 'write' => [{'job' => child.id, 'inport' => 'inport1', 'data' => [1,2]},
87
+ {'job' => child.id, 'outport' => 'outport1', 'data' => [3,4]},
88
+ ]}]
89
+ end
90
+ end
91
+
92
+ describe '#for_inputs' do
93
+ it 'does nothing if no ports provided' do
94
+ expect {|block| @worker.for_inputs(&block)}.not_to yield_control
95
+ end
96
+
97
+ it 'yields data from input ports' do
98
+ @job.input(:in1).write 1
99
+ @job.input(:in1).write 'a'
100
+ @job.input(:in2).write [2, 3]
101
+ @job.input(:in2).write foo: 123
102
+ expect {|block| @worker.for_inputs(:in1, :in2, &block)}.to yield_successive_args([1, [2,3]], ['a', {'foo' => 123}])
103
+ end
104
+
105
+ it 'logs input and output from them' do
106
+ now = Time.now
107
+ allow(Time).to receive(:now) { now }
108
+ @job.input(:in1).write 1
109
+ @job.input(:in1).write 2
110
+ @job.input(:in2).write ['a', 'b']
111
+ @job.input(:in2).write ['c', 'd']
112
+ SideJob.logs(clear: true)
113
+ @worker.for_inputs(:in1, :in2) do |in1, in2|
114
+ @worker.output(:out1).write [in1, in2[0]]
115
+ end
116
+ expect(SideJob.logs).to eq([{'timestamp' => SideJob.timestamp, 'job' => @job.id, 'read' => [{'job' => @job.id, 'inport' => 'in1', 'data' => [1]}, {'job' => @job.id, 'inport' => 'in2', 'data' => [['a', 'b']]}], 'write' => [{'job' => @job.id, 'outport' => 'out1', 'data' => [[1, 'a']]}]},
117
+ {'timestamp' => SideJob.timestamp, 'job' => @job.id, 'read' => [{'job' => @job.id, 'inport' => 'in1', 'data' => [2]}, {'job' => @job.id, 'inport' => 'in2', 'data' => [['c', 'd']]}], 'write' => [{'job' => @job.id, 'outport' => 'out1', 'data' => [[2, 'c']]}]},
118
+ ])
119
+ end
120
+
121
+ it 'suspends on partial inputs' do
122
+ @job.input(:in1).write 1
123
+ @job.input(:in2).write [2, 3]
124
+ @job.input(:in2).write 3
125
+ expect {
126
+ expect {|block| @worker.for_inputs(:in1, :in2, &block)}.to yield_successive_args([1, [2,3]])
127
+ }.to raise_error(SideJob::Worker::Suspended)
128
+ end
129
+
130
+ it 'returns data from memory input ports' do
131
+ @job.input(:memory).write 1
132
+ @job.input(:in2).write [2, 3]
133
+ @job.input(:in2).write 3
134
+ expect {|block| @worker.for_inputs(:memory, :in2, &block)}.to yield_successive_args([1, [2,3]], [1, 3])
135
+ end
136
+
137
+ it 'does not suspend if there is only data on memory port' do
138
+ @job.input(:memory).write 1
139
+ expect {|block| @worker.for_inputs(:memory, :in2, &block)}.not_to yield_control
140
+ end
141
+
142
+ it 'allows for null default values' do
143
+ @job.input(:default_null).write 1
144
+ @job.input(:in2).write [2, 3]
145
+ @job.input(:in2).write 3
146
+ expect {|block| @worker.for_inputs(:default_null, :in2, &block)}.to yield_successive_args([1, [2,3]], [nil, 3])
147
+ end
148
+
149
+ it 'raises error if all ports have defaults' do
150
+ @job.input(:memory).write true
151
+ expect {|block| @worker.for_inputs(:memory, :default, &block)}.to raise_error
152
+ end
153
+ end
154
+
155
+ describe '#set' do
156
+ it 'can save state in redis' do
157
+ @worker.set(test: 'data', test2: 123)
158
+ state = JSON.parse(SideJob.redis.hget('jobs', @worker.id))
159
+ expect(state['test']).to eq 'data'
160
+ expect(state['test2']).to eq 123
161
+
162
+ # test updating
163
+ @worker.set(test: 'data2')
164
+ state = JSON.parse(SideJob.redis.hget('jobs', @worker.id))
165
+ expect(state['test']).to eq 'data2'
166
+ end
167
+
168
+ it 'can update values' do
169
+ 3.times do |i|
170
+ @worker.set key: i
171
+ @worker.reload
172
+ expect(@worker.get(:key)).to eq i
173
+ state = JSON.parse(SideJob.redis.hget('jobs', @worker.id))
174
+ expect(state['key']).to eq i
175
+ end
176
+ end
177
+
178
+ it 'raises error if job no longer exists' do
179
+ @worker.status = 'terminated'
180
+ SideJob.find(@worker.id).delete
181
+ expect { @worker.set key: 123 }.to raise_error
182
+ end
183
+ end
184
+
185
+ describe '#unset' do
186
+ it 'unsets fields' do
187
+ @worker.set(a: 123, b: 456, c: 789)
188
+ @worker.unset('a', :b)
189
+ expect(@worker.get(:a)).to eq nil
190
+ expect(@worker.get(:b)).to eq nil
191
+ expect(@worker.get(:c)).to eq 789
192
+ end
193
+
194
+ it 'raises error if job no longer exists' do
195
+ @worker.status = 'terminated'
196
+ @worker.set a: 123
197
+ SideJob.find(@worker.id).delete
198
+ expect { @worker.unset(:a) }.to raise_error
199
+ end
200
+ end
201
+ end
@@ -0,0 +1,182 @@
1
+ require 'spec_helper'
2
+
3
+ describe SideJob do
4
+ describe '.redis' do
5
+ it 'returns Redis instance via Sidekiq' do
6
+ r1 = SideJob.redis {|redis| redis}
7
+ r2 = Sidekiq.redis {|redis| redis}
8
+ expect(r1).to be(r2)
9
+ end
10
+
11
+ it 'returns Redis without block' do
12
+ expect(SideJob.redis {|redis| redis}).to be(SideJob.redis)
13
+ end
14
+ end
15
+
16
+ describe '.redis=' do
17
+ it 'sets redis url' do
18
+ original = SideJob.redis.client.options[:url]
19
+ SideJob.redis = {url: 'redis://myredis:1234/10'}
20
+ expect(SideJob.redis.client.options[:url]).to eq('redis://myredis:1234/10')
21
+ expect(SideJob.redis.client.options[:host]).to eq('myredis')
22
+ expect(SideJob.redis.client.options[:port]).to eq(1234)
23
+ expect(SideJob.redis.client.options[:db]).to eq(10)
24
+ SideJob.redis = {url: original}
25
+ end
26
+ end
27
+
28
+ describe '.queue' do
29
+ it 'raises an error if no worker registered for specified queue/class' do
30
+ expect { SideJob.queue('unknownq', 'TestWorker') }.to raise_error
31
+ expect { SideJob.queue('testq', 'UnknownWorker') }.to raise_error
32
+ end
33
+
34
+ it 'queues a sidekiq job' do
35
+ expect {
36
+ job = SideJob.queue('testq', 'TestWorker')
37
+ expect(job.exists?).to be true
38
+ expect(job.status).to eq 'queued'
39
+ job = Sidekiq::Queue.new('testq').find_job(job.id)
40
+ expect(job.queue).to eq('testq')
41
+ expect(job.klass).to eq('TestWorker')
42
+ expect(job.args).to eq([])
43
+ }.to change {Sidekiq::Stats.new.enqueued}.by(1)
44
+ end
45
+
46
+ it 'generates an incrementing job id from 1' do
47
+ job = SideJob.queue('testq', 'TestWorker')
48
+ expect(job.id).to eq('1')
49
+ job = SideJob.queue('testq', 'TestWorker')
50
+ expect(job.id).to eq('2')
51
+ end
52
+
53
+ it 'stores created at timestamp' do
54
+ now = Time.now
55
+ allow(Time).to receive(:now) { now }
56
+ job = SideJob.queue('testq', 'TestWorker')
57
+ expect(job.get(:created_at)).to eq(SideJob.timestamp)
58
+ end
59
+
60
+ it 'can specify job args' do
61
+ job = SideJob.queue('testq', 'TestWorker', args: [1,2])
62
+ expect(job.status).to eq 'queued'
63
+ expect(job.get(:args)).to eq [1,2]
64
+ expect_any_instance_of(TestWorker).to receive(:perform).with(1, 2)
65
+ SideJob::Worker.drain_queue
66
+ end
67
+
68
+ it 'can specify job parent' do
69
+ expect {
70
+ parent = SideJob.queue('testq', 'TestWorker')
71
+ job = SideJob.queue('testq', 'TestWorker', parent: parent, name: 'child1')
72
+ expect(job.status).to eq 'queued'
73
+ expect(job.parent).to eq(parent)
74
+ expect(parent.child('child1')).to eq job
75
+ expect(SideJob.redis.lrange("#{job.redis_key}:ancestors", 0, -1)).to eq([parent.id])
76
+ }.to change {Sidekiq::Stats.new.enqueued}.by(2)
77
+ end
78
+
79
+ it 'raises an error if name: option not specified with parent' do
80
+ parent = SideJob.queue('testq', 'TestWorker')
81
+ expect { SideJob.queue('testq', 'TestWorker', parent: parent) }.to raise_error
82
+ end
83
+
84
+ it 'raises an error if name: name is not unique' do
85
+ parent = SideJob.queue('testq', 'TestWorker')
86
+ SideJob.queue('testq', 'TestWorker', parent: parent, name: 'child')
87
+ expect { SideJob.queue('testq', 'TestWorker', parent: parent, name: 'child') }.to raise_error
88
+ end
89
+
90
+ it 'sets ancestor tree correctly' do
91
+ j1 = SideJob.queue('testq', 'TestWorker')
92
+ j2 = SideJob.queue('testq', 'TestWorker', parent: j1, name: 'child1')
93
+ j3 = SideJob.queue('testq', 'TestWorker', parent: j2, name: 'child1')
94
+ expect(SideJob.redis.lrange("#{j3.redis_key}:ancestors", 0, -1)).to eq([j2.id, j1.id])
95
+ end
96
+
97
+ it 'can add a port via inports configuration' do
98
+ job = SideJob.queue('testq', 'TestWorker', inports: {myport: {default: [1,2]}})
99
+ expect(job.status).to eq 'queued'
100
+ expect(job.input(:myport).read).to eq [1, 2]
101
+ end
102
+
103
+ it 'can set the port mode via inports configuration' do
104
+ job = SideJob.queue('testq', 'TestWorker', inports: {queue: {mode: 'queue'}})
105
+ expect(job.status).to eq 'queued'
106
+ expect(job.input(:queue).mode).to be :queue
107
+ end
108
+
109
+ it 'can add a port via outports configuration' do
110
+ job = SideJob.queue('testq', 'TestWorker', outports: {myport: {}})
111
+ expect(job.status).to eq 'queued'
112
+ expect(job.outports.map(&:name).include?(:myport)).to be true
113
+ end
114
+
115
+ it 'can specify a job time' do
116
+ at = Time.now.to_f + 1000
117
+ expect {
118
+ job = SideJob.queue('testq', 'TestWorker', at: at)
119
+ expect(job.status).to eq 'queued'
120
+ expect(Sidekiq::ScheduledSet.new.find_job(job.id).at).to eq(Time.at(at))
121
+ }.to change {Sidekiq::Stats.new.scheduled_size}.by(1)
122
+ end
123
+
124
+ it 'can specify a by string' do
125
+ job = SideJob.queue('testq', 'TestWorker', by: 'test:sidejob')
126
+ expect(job.get(:created_by)).to eq 'test:sidejob'
127
+ end
128
+
129
+ it 'defaults to empty by string' do
130
+ job = SideJob.queue('testq', 'TestWorker')
131
+ expect(job.get(:created_by)).to be nil
132
+ end
133
+ end
134
+
135
+ describe '.find' do
136
+ it 'returns a job object by id' do
137
+ job = SideJob.queue('testq', 'TestWorker')
138
+ expect(SideJob.find(job.id)).to eq(job)
139
+ end
140
+
141
+ it 'returns nil if the job does not exist' do
142
+ expect(SideJob.find('job')).to be_nil
143
+ end
144
+ end
145
+
146
+ describe '.timestamp' do
147
+ it 'returns subseconds' do
148
+ expect(SideJob.timestamp).to match /T\d\d:\d\d:\d\d\./
149
+ end
150
+ end
151
+
152
+ describe '.log' do
153
+ it 'adds a timestamp to log entries' do
154
+ now = Time.now
155
+ allow(Time).to receive(:now) { now }
156
+ SideJob.log({abc: 123})
157
+ log = SideJob.redis.rpop 'jobs:logs'
158
+ expect(JSON.parse(log)).to eq({'abc' => 123, 'timestamp' => SideJob.timestamp})
159
+ end
160
+ end
161
+
162
+ describe '.logs' do
163
+ before do
164
+ now = Time.now
165
+ allow(Time).to receive(:now) { now }
166
+ SideJob.log({abc: 123})
167
+ end
168
+
169
+ it 'returns and clears all logs' do
170
+ expect(SideJob.logs).to eq([{'abc' => 123, 'timestamp' => SideJob.timestamp}])
171
+ SideJob.log({xyz: 456})
172
+ expect(SideJob.logs).to eq([{'xyz' => 456, 'timestamp' => SideJob.timestamp}])
173
+ end
174
+
175
+ it 'returns and leaves logs' do
176
+ expect(SideJob.logs(clear: false)).to eq([{'abc' => 123, 'timestamp' => SideJob.timestamp}])
177
+ SideJob.log({xyz: 456})
178
+ expect(SideJob.logs(clear: false)).to eq([{'abc' => 123, 'timestamp' => SideJob.timestamp},
179
+ {'xyz' => 456, 'timestamp' => SideJob.timestamp},])
180
+ end
181
+ end
182
+ end
@@ -0,0 +1,21 @@
1
+ require 'simplecov'
2
+ SimpleCov.start
3
+
4
+ require 'bundler/setup'
5
+ require 'rspec/core'
6
+ require 'pry'
7
+ require 'sidejob'
8
+ require 'sidejob/testing'
9
+
10
+ # set default redis to something other than database 0 to avoid accidentally clearing a redis with valuable data
11
+ SideJob.redis = {url: 'redis://localhost:6379/6'}
12
+
13
+ Dir[File.dirname(__FILE__) + '/support/*.rb'].each {|file| require file }
14
+
15
+ RSpec.configure do |config|
16
+ config.order = 'random'
17
+ config.before do
18
+ SideJob.redis.flushdb
19
+ SideJob::Worker.register_all 'testq'
20
+ end
21
+ end
@@ -0,0 +1,17 @@
1
+ class TestSum
2
+ include SideJob::Worker
3
+ register(
4
+ inports: {
5
+ ready: {},
6
+ in: {},
7
+ },
8
+ outports: {
9
+ sum: {},
10
+ }
11
+ )
12
+ def perform
13
+ suspend unless input(:ready).data?
14
+ sum = input(:in).inject(&:+)
15
+ output(:sum).write sum
16
+ end
17
+ end
@@ -0,0 +1,6 @@
1
+ class TestWorker
2
+ include SideJob::Worker
3
+ register
4
+ def perform(*args)
5
+ end
6
+ end
metadata ADDED
@@ -0,0 +1,140 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: sidejob
3
+ version: !ruby/object:Gem::Version
4
+ version: 3.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Austin Che
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-11-09 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: sidekiq
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 3.2.5
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 3.2.5
27
+ - !ruby/object:Gem::Dependency
28
+ name: pry
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
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: simplecov
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
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: yard
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
+ description:
84
+ email:
85
+ - austin@ginkgobioworks.com
86
+ executables: []
87
+ extensions: []
88
+ extra_rdoc_files: []
89
+ files:
90
+ - ".gitignore"
91
+ - ".rspec"
92
+ - Gemfile
93
+ - Gemfile.lock
94
+ - README.md
95
+ - bin/build
96
+ - bin/console
97
+ - lib/sidejob.rb
98
+ - lib/sidejob/job.rb
99
+ - lib/sidejob/port.rb
100
+ - lib/sidejob/server_middleware.rb
101
+ - lib/sidejob/testing.rb
102
+ - lib/sidejob/version.rb
103
+ - lib/sidejob/worker.rb
104
+ - sidejob.gemspec
105
+ - spec/integration/fib_spec.rb
106
+ - spec/integration/sum_spec.rb
107
+ - spec/sidejob/job_spec.rb
108
+ - spec/sidejob/port_spec.rb
109
+ - spec/sidejob/server_middleware_spec.rb
110
+ - spec/sidejob/testing_spec.rb
111
+ - spec/sidejob/worker_spec.rb
112
+ - spec/sidejob_spec.rb
113
+ - spec/spec_helper.rb
114
+ - spec/support/test_sum.rb
115
+ - spec/support/test_worker.rb
116
+ homepage:
117
+ licenses: []
118
+ metadata: {}
119
+ post_install_message:
120
+ rdoc_options: []
121
+ require_paths:
122
+ - lib
123
+ required_ruby_version: !ruby/object:Gem::Requirement
124
+ requirements:
125
+ - - ">="
126
+ - !ruby/object:Gem::Version
127
+ version: '0'
128
+ required_rubygems_version: !ruby/object:Gem::Requirement
129
+ requirements:
130
+ - - ">="
131
+ - !ruby/object:Gem::Version
132
+ version: '0'
133
+ requirements: []
134
+ rubyforge_project:
135
+ rubygems_version: 2.2.2
136
+ signing_key:
137
+ specification_version: 4
138
+ summary: Use SideJob to run sidekiq jobs with a flow-based model
139
+ test_files: []
140
+ has_rdoc: