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.
- checksums.yaml +7 -0
- data/.gitignore +5 -0
- data/.rspec +2 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +61 -0
- data/README.md +128 -0
- data/bin/build +11 -0
- data/bin/console +7 -0
- data/lib/sidejob/job.rb +425 -0
- data/lib/sidejob/port.rb +206 -0
- data/lib/sidejob/server_middleware.rb +117 -0
- data/lib/sidejob/testing.rb +54 -0
- data/lib/sidejob/version.rb +4 -0
- data/lib/sidejob/worker.rb +133 -0
- data/lib/sidejob.rb +116 -0
- data/sidejob.gemspec +21 -0
- data/spec/integration/fib_spec.rb +51 -0
- data/spec/integration/sum_spec.rb +39 -0
- data/spec/sidejob/job_spec.rb +543 -0
- data/spec/sidejob/port_spec.rb +452 -0
- data/spec/sidejob/server_middleware_spec.rb +254 -0
- data/spec/sidejob/testing_spec.rb +108 -0
- data/spec/sidejob/worker_spec.rb +201 -0
- data/spec/sidejob_spec.rb +182 -0
- data/spec/spec_helper.rb +21 -0
- data/spec/support/test_sum.rb +17 -0
- data/spec/support/test_worker.rb +6 -0
- metadata +140 -0
@@ -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
|
data/spec/spec_helper.rb
ADDED
@@ -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
|
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:
|