sidejob 4.0.2 → 4.1.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 +4 -4
- data/README.md +38 -15
- data/lib/sidejob.rb +82 -26
- data/lib/sidejob/job.rb +121 -33
- data/lib/sidejob/port.rb +153 -50
- data/lib/sidejob/server_middleware.rb +16 -4
- data/lib/sidejob/testing.rb +6 -13
- data/lib/sidejob/version.rb +1 -1
- data/lib/sidejob/worker.rb +5 -5
- data/spec/integration/channels_spec.rb +36 -0
- data/spec/sidejob/job_spec.rb +141 -8
- data/spec/sidejob/port_spec.rb +208 -68
- data/spec/sidejob/server_middleware_spec.rb +30 -15
- data/spec/sidejob/testing_spec.rb +0 -18
- data/spec/sidejob/worker_spec.rb +11 -6
- data/spec/sidejob_spec.rb +85 -33
- data/web/Gemfile.lock +2 -2
- data/web/app.rb +22 -19
- metadata +3 -2
@@ -17,14 +17,6 @@ describe 'SideJob testing helpers' do
|
|
17
17
|
end
|
18
18
|
end
|
19
19
|
|
20
|
-
class TestMysteriousFailure
|
21
|
-
include SideJob::Worker
|
22
|
-
register
|
23
|
-
def perform
|
24
|
-
self.status = 'failed'
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
20
|
describe 'SideJob::Worker.drain_queue' do
|
29
21
|
it 'runs jobs' do
|
30
22
|
job = SideJob.queue('testq', 'TestSum')
|
@@ -50,11 +42,6 @@ describe 'SideJob testing helpers' do
|
|
50
42
|
expect { SideJob::Worker.drain_queue }.to raise_error(RuntimeError, 'bad error')
|
51
43
|
end
|
52
44
|
|
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
45
|
it 'can disable raising of errors' do
|
59
46
|
job = SideJob.queue('testq', 'TestFailure')
|
60
47
|
expect { SideJob::Worker.drain_queue(errors: false) }.not_to raise_error
|
@@ -95,11 +82,6 @@ describe 'SideJob testing helpers' do
|
|
95
82
|
expect { job.run_inline }.to raise_error(RuntimeError, 'bad error')
|
96
83
|
end
|
97
84
|
|
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
85
|
it 'can disable raising of errors' do
|
104
86
|
job = SideJob.queue('testq', 'TestFailure')
|
105
87
|
expect { job.run_inline(errors: false) }.not_to raise_error
|
data/spec/sidejob/worker_spec.rb
CHANGED
@@ -20,6 +20,11 @@ describe SideJob::Worker do
|
|
20
20
|
SideJob::Worker.register_all('q1')
|
21
21
|
expect(SideJob.redis.hget('workers:q1', 'foo')).to be nil
|
22
22
|
end
|
23
|
+
|
24
|
+
it 'publishes message containing worker registry' do
|
25
|
+
expect(SideJob).to receive(:publish).with('/sidejob/workers/q1', SideJob::Worker.registry)
|
26
|
+
SideJob::Worker.register_all('q1')
|
27
|
+
end
|
23
28
|
end
|
24
29
|
|
25
30
|
describe '.config' do
|
@@ -75,19 +80,19 @@ describe SideJob::Worker do
|
|
75
80
|
end
|
76
81
|
|
77
82
|
it 'logs input and output from them' do
|
78
|
-
now = Time.now
|
79
|
-
allow(Time).to receive(:now) { now }
|
80
83
|
@job.input(:in1).write 1
|
81
84
|
@job.input(:in1).write 2
|
82
85
|
@job.input(:in2).write ['a', 'b']
|
83
86
|
@job.input(:in2).write ['c', 'd']
|
84
|
-
SideJob.
|
87
|
+
expect(SideJob).to receive(:log).with({
|
88
|
+
read: [{job: @job.id, inport: :in1, data: [1]}, {job: @job.id, inport: :in2, data: [['a', 'b']]}],
|
89
|
+
write: [{job: @job.id, outport: :out1, data: [[1, 'a']]}]})
|
90
|
+
expect(SideJob).to receive(:log).with({
|
91
|
+
read: [{job: @job.id, inport: :in1, data: [2]}, {job: @job.id, inport: :in2, data: [['c', 'd']]}],
|
92
|
+
write: [{job: @job.id, outport: :out1, data: [[2, 'c']]}]})
|
85
93
|
@worker.for_inputs(:in1, :in2) do |in1, in2|
|
86
94
|
@worker.output(:out1).write [in1, in2[0]]
|
87
95
|
end
|
88
|
-
expect(SideJob.logs).to eq([{'timestamp' => SideJob.timestamp, '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']]}]},
|
89
|
-
{'timestamp' => SideJob.timestamp, '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']]}]},
|
90
|
-
])
|
91
96
|
end
|
92
97
|
|
93
98
|
it 'suspends on partial inputs' do
|
data/spec/sidejob_spec.rb
CHANGED
@@ -54,13 +54,13 @@ describe SideJob do
|
|
54
54
|
now = Time.now
|
55
55
|
allow(Time).to receive(:now) { now }
|
56
56
|
job = SideJob.queue('testq', 'TestWorker')
|
57
|
-
expect(job.
|
57
|
+
expect(job.info[:created_at]).to eq(SideJob.timestamp)
|
58
58
|
end
|
59
59
|
|
60
60
|
it 'can specify job args' do
|
61
61
|
job = SideJob.queue('testq', 'TestWorker', args: [1,2])
|
62
62
|
expect(job.status).to eq 'queued'
|
63
|
-
expect(job.
|
63
|
+
expect(job.info[:args]).to eq [1,2]
|
64
64
|
expect_any_instance_of(TestWorker).to receive(:perform).with(1, 2)
|
65
65
|
SideJob::Worker.drain_queue
|
66
66
|
end
|
@@ -109,7 +109,7 @@ describe SideJob do
|
|
109
109
|
|
110
110
|
it 'can specify a by string' do
|
111
111
|
job = SideJob.queue('testq', 'TestWorker', by: 'test:sidejob')
|
112
|
-
expect(job.
|
112
|
+
expect(job.info[:created_by]).to eq 'test:sidejob'
|
113
113
|
end
|
114
114
|
|
115
115
|
it 'defaults to empty by string' do
|
@@ -124,6 +124,12 @@ describe SideJob do
|
|
124
124
|
expect(SideJob.find(job.id)).to eq(job)
|
125
125
|
end
|
126
126
|
|
127
|
+
it 'returns a job object by alias' do
|
128
|
+
job = SideJob.queue('testq', 'TestWorker')
|
129
|
+
job.add_alias 'myjob'
|
130
|
+
expect(SideJob.find('myjob')).to eq(job)
|
131
|
+
end
|
132
|
+
|
127
133
|
it 'returns nil if the job does not exist' do
|
128
134
|
expect(SideJob.find('job')).to be_nil
|
129
135
|
end
|
@@ -136,70 +142,116 @@ describe SideJob do
|
|
136
142
|
end
|
137
143
|
|
138
144
|
describe '.log' do
|
139
|
-
it '
|
145
|
+
it 'can log arbitrary entry hash' do
|
140
146
|
now = Time.now
|
141
147
|
allow(Time).to receive(:now) { now }
|
148
|
+
expect(SideJob).to receive(:publish).with('/sidejob/log', {abc: 123, timestamp: SideJob.timestamp})
|
142
149
|
SideJob.log({abc: 123})
|
143
|
-
log = SideJob.redis.rpop 'jobs:logs'
|
144
|
-
expect(JSON.parse(log)).to eq({'abc' => 123, 'timestamp' => SideJob.timestamp})
|
145
150
|
end
|
146
|
-
end
|
147
151
|
|
148
|
-
|
149
|
-
before do
|
152
|
+
it 'can log exceptions' do
|
150
153
|
now = Time.now
|
151
154
|
allow(Time).to receive(:now) { now }
|
152
|
-
|
155
|
+
exception = RuntimeError.new('err')
|
156
|
+
expect(SideJob).to receive(:publish).with('/sidejob/log', {error: 'err', timestamp: SideJob.timestamp})
|
157
|
+
SideJob.log(exception)
|
153
158
|
end
|
154
159
|
|
155
|
-
it '
|
156
|
-
|
157
|
-
|
158
|
-
expect(SideJob
|
160
|
+
it 'can log string messages' do
|
161
|
+
now = Time.now
|
162
|
+
allow(Time).to receive(:now) { now }
|
163
|
+
expect(SideJob).to receive(:publish).with('/sidejob/log', {message: 'hello', timestamp: SideJob.timestamp})
|
164
|
+
SideJob.log 'hello'
|
159
165
|
end
|
160
166
|
|
161
|
-
it '
|
162
|
-
|
163
|
-
SideJob.log({
|
164
|
-
expect(SideJob.logs(clear: false)).to eq([{'abc' => 123, 'timestamp' => SideJob.timestamp},
|
165
|
-
{'xyz' => 456, 'timestamp' => SideJob.timestamp},])
|
167
|
+
it 'does not generate an infinite publish loop for port subscriptions on /sidejob/log' do
|
168
|
+
job = SideJob.queue('testq', 'TestWorker', inports: {port1: {channels: ['/sidejob/log', '/']}})
|
169
|
+
SideJob.log({test: 1})
|
166
170
|
end
|
167
171
|
end
|
168
172
|
|
169
|
-
describe '.
|
173
|
+
describe '.context' do
|
170
174
|
before do
|
171
175
|
now = Time.now
|
172
176
|
allow(Time).to receive(:now) { now }
|
173
177
|
end
|
174
178
|
|
175
|
-
it 'adds
|
176
|
-
SideJob.
|
179
|
+
it 'adds data to logs within the group' do
|
180
|
+
expect(SideJob).to receive(:publish).with('/sidejob/log', {data1: 1, data2: 2, abc: 123, timestamp: SideJob.timestamp})
|
181
|
+
SideJob.context(data1: 1, data2: 2) do
|
177
182
|
SideJob.log({abc: 123})
|
178
|
-
expect(SideJob.logs).to eq([{'data1' => 1, 'data2' => 2, 'abc' => 123, 'timestamp' => SideJob.timestamp}])
|
179
183
|
end
|
180
184
|
end
|
181
185
|
|
182
|
-
it 'does not add
|
183
|
-
SideJob.
|
186
|
+
it 'does not add data to logs outside of the group' do
|
187
|
+
expect(SideJob).to receive(:publish).with('/sidejob/log', {abc: 123, timestamp: SideJob.timestamp})
|
188
|
+
SideJob.context(data1: 1, data2: 2) {}
|
184
189
|
SideJob.log({abc: 123})
|
185
|
-
expect(SideJob.logs).to eq([{'abc' => 123, 'timestamp' => SideJob.timestamp}])
|
186
190
|
end
|
187
191
|
|
188
192
|
it 'can be nested' do
|
189
|
-
SideJob.
|
193
|
+
expect(SideJob).to receive(:publish).with('/sidejob/log', {data1: 1, timestamp: SideJob.timestamp, x: 1})
|
194
|
+
expect(SideJob).to receive(:publish).with('/sidejob/log', {data1: 1, data2: 2, timestamp: SideJob.timestamp, x: 2})
|
195
|
+
expect(SideJob).to receive(:publish).with('/sidejob/log', {data1: 1, timestamp: SideJob.timestamp, x: 3})
|
196
|
+
expect(SideJob).to receive(:publish).with('/sidejob/log', {timestamp: SideJob.timestamp, x: 4})
|
197
|
+
SideJob.context(data1: 1) do
|
190
198
|
SideJob.log({x: 1})
|
191
|
-
SideJob.
|
199
|
+
SideJob.context(data2: 2) do
|
192
200
|
SideJob.log({x: 2})
|
193
201
|
end
|
194
202
|
SideJob.log({x: 3})
|
195
203
|
end
|
196
204
|
SideJob.log({x: 4})
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
describe '.publish' do
|
209
|
+
it 'publishes message to channel ignoring hierarchy using redis pubsub' do
|
210
|
+
Timeout::timeout(3) do
|
211
|
+
subscribed = false
|
212
|
+
t = Thread.new do
|
213
|
+
redis = SideJob.redis.dup
|
214
|
+
redis.psubscribe('*') do |on|
|
215
|
+
on.psubscribe do |pattern, total|
|
216
|
+
subscribed = true
|
217
|
+
end
|
218
|
+
|
219
|
+
on.pmessage do |pattern, channel, message|
|
220
|
+
expect(JSON.parse(message)).to eq [1,2]
|
221
|
+
expect(channel).to eq '/namespace/mychannel'
|
222
|
+
redis.punsubscribe
|
223
|
+
end
|
224
|
+
end
|
225
|
+
end
|
226
|
+
|
227
|
+
Thread.pass until subscribed
|
228
|
+
SideJob.publish '/namespace/mychannel', [1,2]
|
229
|
+
t.join
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
233
|
+
it 'writes to subscribed jobs' do
|
234
|
+
job = SideJob.queue('testq', 'TestWorker', inports: {myport: {channels: ['/namespace/mychannel']}, yourport: {channels: ['/namespace']}})
|
235
|
+
SideJob.publish('/namespace/mychannel', [1,2])
|
236
|
+
expect(job.input(:myport).entries).to eq [[1,2]]
|
237
|
+
expect(job.input(:yourport).entries).to eq [[1,2]]
|
238
|
+
end
|
239
|
+
|
240
|
+
it 'includes original channel in context' do
|
241
|
+
job = SideJob.queue('testq', 'TestWorker', inports: {myport: {channels: ['/namespace']}})
|
242
|
+
SideJob.publish('/namespace/mychannel', [1,2])
|
243
|
+
data = job.input(:myport).read
|
244
|
+
expect(data).to eq [1,2]
|
245
|
+
expect(data.sidejob_context).to eq({'channel' => '/namespace/mychannel'})
|
246
|
+
end
|
197
247
|
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
248
|
+
it 'removes jobs that are no longer subscribed' do
|
249
|
+
job = SideJob.queue('testq', 'TestWorker', inports: {myport: {channels: ['/namespace/mychannel']}})
|
250
|
+
job.input(:myport).channels = []
|
251
|
+
expect(SideJob.redis.smembers('channel:/namespace/mychannel')).to eq [job.id.to_s]
|
252
|
+
SideJob.publish('/namespace/mychannel', [1,2])
|
253
|
+
expect(SideJob.redis.smembers('channel:/namespace/mychannel')).to eq []
|
254
|
+
expect(job.input(:myport).size).to eq 0
|
203
255
|
end
|
204
256
|
end
|
205
257
|
end
|
data/web/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: ..
|
3
3
|
specs:
|
4
|
-
sidejob (4.0
|
4
|
+
sidejob (4.1.0)
|
5
5
|
sidekiq
|
6
6
|
|
7
7
|
GEM
|
@@ -11,7 +11,7 @@ GEM
|
|
11
11
|
timers (~> 4.0.0)
|
12
12
|
connection_pool (2.2.0)
|
13
13
|
hitimes (1.2.2)
|
14
|
-
json (1.8.
|
14
|
+
json (1.8.3)
|
15
15
|
puma (2.10.2)
|
16
16
|
rack (>= 1.1, < 2.0)
|
17
17
|
rack (1.6.0)
|
data/web/app.rb
CHANGED
@@ -12,9 +12,25 @@ class SideJob::Web < Sinatra::Base
|
|
12
12
|
200
|
13
13
|
end
|
14
14
|
|
15
|
-
# provide
|
15
|
+
# only provide version for now
|
16
16
|
get '/' do
|
17
|
-
{ version:
|
17
|
+
{ version: SideJob::VERSION }.to_json
|
18
|
+
end
|
19
|
+
|
20
|
+
# publish a message to a channel
|
21
|
+
post '/publish' do
|
22
|
+
api_call do |params|
|
23
|
+
SideJob.publish params['channel'], params['message']
|
24
|
+
nil
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
# add a log entry
|
29
|
+
post '/log' do
|
30
|
+
api_call do |params|
|
31
|
+
SideJob.log(params['entry'])
|
32
|
+
nil
|
33
|
+
end
|
18
34
|
end
|
19
35
|
|
20
36
|
# queue a new job
|
@@ -80,12 +96,13 @@ class SideJob::Web < Sinatra::Base
|
|
80
96
|
if data == SideJob::Port::None
|
81
97
|
{}
|
82
98
|
else
|
83
|
-
{ data: data }
|
99
|
+
{ data: data, context: data.sidejob_context }
|
84
100
|
end
|
85
101
|
|
86
102
|
# read all and return an array of data
|
87
103
|
when 'entries'
|
88
|
-
|
104
|
+
entries = port.entries
|
105
|
+
{ entries: entries.map {|x| { data: x.data, context: x.sidejob_context } } }
|
89
106
|
|
90
107
|
# port write
|
91
108
|
when 'write'
|
@@ -155,20 +172,6 @@ class SideJob::Web < Sinatra::Base
|
|
155
172
|
end
|
156
173
|
end
|
157
174
|
|
158
|
-
# return all logs
|
159
|
-
get '/logs' do
|
160
|
-
api_call do |params|
|
161
|
-
SideJob.logs(clear: params['clear'] || false)
|
162
|
-
end
|
163
|
-
end
|
164
|
-
|
165
|
-
# add a log entry
|
166
|
-
post '/logs' do
|
167
|
-
api_call do |params|
|
168
|
-
SideJob.log(params['entry'])
|
169
|
-
end
|
170
|
-
end
|
171
|
-
|
172
175
|
private
|
173
176
|
|
174
177
|
def job_api(&block)
|
@@ -185,7 +188,7 @@ class SideJob::Web < Sinatra::Base
|
|
185
188
|
begin
|
186
189
|
request.body.rewind
|
187
190
|
params = JSON.parse(request.body.read) rescue {}
|
188
|
-
SideJob.
|
191
|
+
SideJob.context(params['context'] || {}) do
|
189
192
|
(yield params).to_json
|
190
193
|
end
|
191
194
|
rescue => e
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sidejob
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 4.0
|
4
|
+
version: 4.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Austin Che
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-09-07 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: sidekiq
|
@@ -102,6 +102,7 @@ files:
|
|
102
102
|
- lib/sidejob/version.rb
|
103
103
|
- lib/sidejob/worker.rb
|
104
104
|
- sidejob.gemspec
|
105
|
+
- spec/integration/channels_spec.rb
|
105
106
|
- spec/integration/fib_spec.rb
|
106
107
|
- spec/integration/sum_spec.rb
|
107
108
|
- spec/sidejob/job_spec.rb
|