sidejob 3.0.1 → 4.0.1
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/Gemfile.lock +5 -5
- data/README.md +10 -14
- data/lib/sidejob.rb +29 -23
- data/lib/sidejob/job.rb +183 -213
- data/lib/sidejob/port.rb +112 -80
- data/lib/sidejob/server_middleware.rb +56 -50
- data/lib/sidejob/testing.rb +0 -2
- data/lib/sidejob/version.rb +1 -1
- data/lib/sidejob/worker.rb +28 -46
- data/spec/integration/fib_spec.rb +8 -4
- data/spec/integration/sum_spec.rb +0 -1
- data/spec/sidejob/job_spec.rb +323 -241
- data/spec/sidejob/port_spec.rb +152 -138
- data/spec/sidejob/server_middleware_spec.rb +27 -47
- data/spec/sidejob/worker_spec.rb +16 -84
- data/spec/sidejob_spec.rb +39 -16
- data/web/Gemfile +6 -0
- data/web/Gemfile.lock +43 -0
- data/web/app.rb +205 -0
- data/web/config.ru +14 -0
- metadata +6 -2
data/spec/sidejob/port_spec.rb
CHANGED
@@ -4,23 +4,19 @@ describe SideJob::Port do
|
|
4
4
|
before do
|
5
5
|
@job = SideJob.queue('testq', 'TestWorker', inports: {
|
6
6
|
port1: {},
|
7
|
-
memory: { mode: :memory },
|
8
7
|
default: { default: 'default' },
|
9
8
|
default_null: { default: nil },
|
10
9
|
default_false: { default: false},
|
11
|
-
memory_with_default: { mode: :memory, default: 'memory default' },
|
12
10
|
}, outports: {
|
13
11
|
out1: {},
|
14
12
|
})
|
15
13
|
@port1 = @job.input(:port1)
|
16
14
|
@out1 = @job.output(:out1)
|
17
|
-
@memory = @job.input(:memory)
|
18
15
|
@default = @job.input(:default)
|
19
16
|
@defaults = [
|
20
17
|
@default,
|
21
18
|
@job.input(:default_null),
|
22
19
|
@job.input(:default_false),
|
23
|
-
@job.input(:memory_with_default)
|
24
20
|
]
|
25
21
|
end
|
26
22
|
|
@@ -32,9 +28,24 @@ describe SideJob::Port do
|
|
32
28
|
it 'raises error if name is empty' do
|
33
29
|
expect { SideJob::Port.new(@job, :in, '')}.to raise_error
|
34
30
|
end
|
31
|
+
|
32
|
+
it 'raises error on non-existent port' do
|
33
|
+
expect { SideJob::Port.new(@job, :in, 'missing')}.to raise_error
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'can dynamically create a port' do
|
37
|
+
@job.inports = {
|
38
|
+
'*' => { default: 123 },
|
39
|
+
}
|
40
|
+
expect(@job.input('abc').default).to eq 123
|
41
|
+
end
|
35
42
|
end
|
36
43
|
|
37
44
|
describe '#==, #eql?' do
|
45
|
+
before do
|
46
|
+
@job.inports = { '*' => {}}
|
47
|
+
end
|
48
|
+
|
38
49
|
it 'two ports with the same job, type, and name are eq' do
|
39
50
|
expect(SideJob::Port.new(@job, :in, :port1)).to eq(@port1)
|
40
51
|
expect(SideJob::Port.new(@job, :in, 'port1')).to eq(@port1)
|
@@ -58,57 +69,6 @@ describe SideJob::Port do
|
|
58
69
|
end
|
59
70
|
end
|
60
71
|
|
61
|
-
describe '#options' do
|
62
|
-
it 'returns port options' do
|
63
|
-
expect(@port1.options).to eq({mode: :queue})
|
64
|
-
expect(@memory.options).to eq({mode: :memory})
|
65
|
-
expect(@default.options).to eq({mode: :queue, default: 'default'})
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
|
-
describe '#options=' do
|
70
|
-
it 'can change mode to memory' do
|
71
|
-
expect(@port1.mode).to eq :queue
|
72
|
-
@port1.options = { mode: :memory }
|
73
|
-
expect(@port1.mode).to eq :memory
|
74
|
-
end
|
75
|
-
|
76
|
-
it 'can change mode to queue' do
|
77
|
-
expect(@memory.mode).to eq :memory
|
78
|
-
@memory.options = { mode: :queue }
|
79
|
-
expect(@memory.mode).to eq :queue
|
80
|
-
end
|
81
|
-
|
82
|
-
it 'can set default value' do
|
83
|
-
expect(@port1.default?).to be false
|
84
|
-
@port1.options = { default: [1,2] }
|
85
|
-
expect(@port1.default).to eq [1,2]
|
86
|
-
expect(@port1.read).to eq [1,2]
|
87
|
-
end
|
88
|
-
|
89
|
-
it 'can remove default value' do
|
90
|
-
expect(@default.default?).to be true
|
91
|
-
@default.options = { }
|
92
|
-
expect(@default.default?).to be false
|
93
|
-
end
|
94
|
-
end
|
95
|
-
|
96
|
-
describe '#mode' do
|
97
|
-
it 'returns nil for non-existent ports' do
|
98
|
-
expect(SideJob::Port.new(@job, :in, 'missing').mode).to be nil
|
99
|
-
end
|
100
|
-
|
101
|
-
it 'returns the port mode for queue ports' do
|
102
|
-
expect(@port1.mode).to eq :queue
|
103
|
-
expect(@default.mode).to eq :queue
|
104
|
-
end
|
105
|
-
|
106
|
-
it 'returns the port mode for memory ports' do
|
107
|
-
expect(@memory.mode).to eq :memory
|
108
|
-
expect(@job.input(:memory_with_default).mode).to eq :memory
|
109
|
-
end
|
110
|
-
end
|
111
|
-
|
112
72
|
describe '#size' do
|
113
73
|
it 'returns 0 when the port is empty' do
|
114
74
|
expect(@port1.size).to eq 0
|
@@ -142,29 +102,23 @@ describe SideJob::Port do
|
|
142
102
|
expect(@port1.data?).to be true
|
143
103
|
end
|
144
104
|
|
145
|
-
it '
|
146
|
-
expect(@memory.data?).to be false
|
147
|
-
@memory.write 1
|
148
|
-
expect(@memory.data?).to be true
|
149
|
-
end
|
150
|
-
|
151
|
-
it 'works when there is a default value on the port' do
|
105
|
+
it 'returns true when there is a default value on the port' do
|
152
106
|
@defaults.each {|port| expect(port.data?).to be true }
|
153
107
|
end
|
154
108
|
end
|
155
109
|
|
156
110
|
describe '#default' do
|
157
|
-
it 'returns nil for no default' do
|
158
|
-
expect(@port1.default).to be nil
|
159
|
-
end
|
160
|
-
|
161
111
|
it 'returns default value' do
|
162
|
-
@port1.
|
112
|
+
@port1.default = [1,2]
|
163
113
|
expect(@port1.default).to eq [1,2]
|
164
114
|
end
|
165
115
|
|
116
|
+
it 'returns None for no default' do
|
117
|
+
expect(@port1.default).to be SideJob::Port::None
|
118
|
+
end
|
119
|
+
|
166
120
|
it 'can return null default value' do
|
167
|
-
@port1.
|
121
|
+
@port1.default = nil
|
168
122
|
expect(@port1.default).to be nil
|
169
123
|
expect(@port1.default?).to be true
|
170
124
|
end
|
@@ -175,17 +129,24 @@ describe SideJob::Port do
|
|
175
129
|
expect(@port1.default?).to be false
|
176
130
|
end
|
177
131
|
|
178
|
-
it 'returns
|
179
|
-
expect(
|
132
|
+
it 'returns true for port with default value' do
|
133
|
+
@defaults.each {|port| expect(port.default?).to be true }
|
180
134
|
end
|
135
|
+
end
|
181
136
|
|
182
|
-
|
183
|
-
|
184
|
-
|
137
|
+
describe '#default=' do
|
138
|
+
it 'can set and overwrite the default' do
|
139
|
+
[true, false, nil, 123, 'abc', {'xyz' => [1,2]}, [5,6]].each do |val|
|
140
|
+
@port1.default = val
|
141
|
+
expect(@port1.default).to eq(val)
|
142
|
+
end
|
185
143
|
end
|
186
144
|
|
187
|
-
it '
|
188
|
-
@
|
145
|
+
it 'can clear the default' do
|
146
|
+
@port1.default = 1234
|
147
|
+
expect(@port1.default?).to be true
|
148
|
+
@port1.default = SideJob::Port::None
|
149
|
+
expect(@port1.default?).to be false
|
189
150
|
end
|
190
151
|
end
|
191
152
|
|
@@ -196,22 +157,14 @@ describe SideJob::Port do
|
|
196
157
|
expect(data).to eq(['"abc"', '123', 'true', 'false', 'null', '{"abc":123}', '[1,{"foo":true}]'])
|
197
158
|
end
|
198
159
|
|
199
|
-
it 'writing to a memory port should only set default value to latest value' do
|
200
|
-
@memory.write 'abc'
|
201
|
-
@memory.write [1, {foo: true}]
|
202
|
-
@memory.write 'latest'
|
203
|
-
expect(@memory.size).to eq 0
|
204
|
-
expect(@memory.default).to eq 'latest'
|
205
|
-
end
|
206
|
-
|
207
160
|
it 'logs writes' do
|
208
161
|
now = Time.now
|
209
162
|
allow(Time).to receive(:now) { now }
|
210
|
-
|
163
|
+
SideJob::Port.log_group do
|
211
164
|
@port1.write 'abc'
|
212
165
|
@port1.write 123
|
213
166
|
end
|
214
|
-
expect(SideJob.logs).to eq [{'timestamp' => SideJob.timestamp, '
|
167
|
+
expect(SideJob.logs).to eq [{'timestamp' => SideJob.timestamp, 'read' => [],
|
215
168
|
'write' => ['job' => @job.id, 'inport' => 'port1', 'data' => ['abc', 123]]}]
|
216
169
|
end
|
217
170
|
|
@@ -219,36 +172,30 @@ describe SideJob::Port do
|
|
219
172
|
expect { SideJob::Port.new(@job, :in, 'foo').write true }.to raise_error
|
220
173
|
end
|
221
174
|
|
222
|
-
it 'raises error if port mode is unknown ' do
|
223
|
-
SideJob.redis.hset "#{@job.redis_key}:inports:mode", 'foo', '???'
|
224
|
-
expect { SideJob::Port.new(@job, :in, 'foo').write true }.to raise_error
|
225
|
-
end
|
226
|
-
|
227
175
|
it 'runs the job if it is an input port' do
|
228
|
-
|
176
|
+
parent = SideJob.queue('testq', 'TestWorker')
|
177
|
+
parent.adopt(@job, 'child')
|
178
|
+
parent.status = 'completed'
|
179
|
+
@job.status = 'completed'
|
229
180
|
@port1.write 3
|
181
|
+
expect(@job.status).to eq 'queued'
|
182
|
+
expect(parent.status).to eq 'completed'
|
230
183
|
end
|
231
184
|
|
232
|
-
it '
|
233
|
-
|
185
|
+
it 'runs the parent job if it is an output port' do
|
186
|
+
parent = SideJob.queue('testq', 'TestWorker')
|
187
|
+
parent.adopt(@job, 'child')
|
188
|
+
parent.status = 'completed'
|
189
|
+
@job.status = 'completed'
|
234
190
|
@out1.write 3
|
235
|
-
|
236
|
-
|
237
|
-
it 'does not run the job if it is a memory port' do
|
238
|
-
expect(@memory.job).not_to receive(:run)
|
239
|
-
@memory.write 3
|
191
|
+
expect(@job.status).to eq 'completed'
|
192
|
+
expect(parent.status).to eq 'queued'
|
240
193
|
end
|
241
194
|
end
|
242
195
|
|
243
196
|
describe '#read' do
|
244
|
-
it 'can
|
245
|
-
expect
|
246
|
-
@port1.write nil
|
247
|
-
expect(@port1.read).to be nil
|
248
|
-
end
|
249
|
-
|
250
|
-
it 'can read data from a queue port' do
|
251
|
-
expect { @port1.read }.to raise_error(EOFError)
|
197
|
+
it 'can read different kinds of data' do
|
198
|
+
expect(@port1.read).to eq SideJob::Port::None
|
252
199
|
['abc', 123, true, false, nil, {}, ['data1', 1, {key: 'val'}]].each {|x| @port1.write x}
|
253
200
|
expect(@port1.size).to be(7)
|
254
201
|
expect(@port1.read).to eq('abc')
|
@@ -258,22 +205,16 @@ describe SideJob::Port do
|
|
258
205
|
expect(@port1.read).to eq(nil)
|
259
206
|
expect(@port1.read).to eq({})
|
260
207
|
expect(@port1.read).to eq(['data1', 1, {'key' => 'val'}])
|
261
|
-
expect
|
208
|
+
expect(@port1.read).to eq SideJob::Port::None
|
262
209
|
expect(@port1.size).to be(0)
|
263
210
|
end
|
264
211
|
|
265
|
-
it 'can read data from a memory port' do
|
266
|
-
expect { @memory.read }.to raise_error(EOFError)
|
267
|
-
5.times {|i| @memory.write i }
|
268
|
-
3.times { expect(@memory.read).to eq(4) }
|
269
|
-
end
|
270
|
-
|
271
212
|
it 'can use default value' do
|
272
213
|
@defaults.each do |port|
|
273
214
|
3.times { expect(port.read).to eq port.default }
|
274
215
|
port.write 'mydata'
|
275
216
|
expect(port.read).to eq 'mydata'
|
276
|
-
3.times { expect(port.read).to eq port.
|
217
|
+
3.times { expect(port.read).to eq port.default }
|
277
218
|
end
|
278
219
|
end
|
279
220
|
|
@@ -292,11 +233,11 @@ describe SideJob::Port do
|
|
292
233
|
allow(Time).to receive(:now) { now }
|
293
234
|
['abc', 123].each {|x| @port1.write x}
|
294
235
|
SideJob.logs
|
295
|
-
|
236
|
+
SideJob::Port.log_group do
|
296
237
|
expect(@port1.read).to eq('abc')
|
297
238
|
expect(@port1.read).to eq(123)
|
298
239
|
end
|
299
|
-
expect(SideJob.logs).to eq [{'timestamp' => SideJob.timestamp,
|
240
|
+
expect(SideJob.logs).to eq [{'timestamp' => SideJob.timestamp,
|
300
241
|
'read' => ['job' => @job.id, 'inport' => 'port1', 'data' => ['abc', 123]],
|
301
242
|
'write' => []}]
|
302
243
|
end
|
@@ -319,52 +260,65 @@ describe SideJob::Port do
|
|
319
260
|
end
|
320
261
|
|
321
262
|
it 'sends data to all destination ports' do
|
322
|
-
dest = [@port1, @
|
263
|
+
dest = [@port1, @default]
|
323
264
|
@out1.write 1
|
324
265
|
@out1.write [2,3]
|
325
266
|
@out1.connect_to dest
|
326
267
|
expect(@port1.read).to eq 1
|
327
268
|
expect(@port1.read).to eq [2,3]
|
328
269
|
expect(@port1.data?).to be false
|
329
|
-
expect(@memory.size).to eq 0
|
330
|
-
expect(@memory.read).to eq [2,3]
|
331
270
|
expect(@default.read).to eq 1
|
332
271
|
expect(@default.read).to eq [2,3]
|
333
272
|
expect(@default.read).to eq 'default'
|
334
273
|
end
|
335
274
|
|
336
275
|
it 'passes port default values to all destinations' do
|
337
|
-
dest = [@port1, @
|
276
|
+
dest = [@port1, @out1]
|
338
277
|
@default.write 1
|
339
278
|
@default.write [2,3]
|
340
279
|
@default.connect_to dest
|
341
280
|
expect(@port1.read).to eq 1
|
342
281
|
expect(@port1.read).to eq [2,3]
|
343
282
|
expect(@port1.default).to eq 'default'
|
344
|
-
expect(@memory.size).to eq 0
|
345
|
-
expect(@memory.default).to eq 'default'
|
346
283
|
expect(@out1.read).to eq 1
|
347
284
|
expect(@out1.read).to eq [2,3]
|
348
285
|
expect(@out1.default).to eq 'default'
|
349
286
|
end
|
350
287
|
|
351
|
-
it 'runs job
|
288
|
+
it 'runs job if the default value has changed' do
|
352
289
|
expect(@port1.job).to receive(:run)
|
290
|
+
@default.connect_to @port1
|
291
|
+
end
|
292
|
+
|
293
|
+
it 'does not run job if the default value has not changed' do
|
294
|
+
@default.connect_to @port1
|
295
|
+
expect(@port1.job).not_to receive(:run)
|
296
|
+
@default.connect_to @port1
|
297
|
+
end
|
298
|
+
|
299
|
+
it 'runs job for normal input port' do
|
353
300
|
@out1.write true
|
301
|
+
expect(@port1.job).to receive(:run)
|
354
302
|
@out1.connect_to @port1
|
355
303
|
end
|
356
304
|
|
305
|
+
it 'runs parent job for outport' do
|
306
|
+
parent = SideJob.queue('testq', 'TestWorker')
|
307
|
+
parent.adopt(@job, 'child')
|
308
|
+
parent.status = 'completed'
|
309
|
+
@job.status = 'completed'
|
310
|
+
j2 = SideJob.queue('testq', 'TestWorker', inports: {in: {}})
|
311
|
+
j2.input(:in).write true
|
312
|
+
j2.input(:in).connect_to @out1
|
313
|
+
expect(@job.status).to eq 'completed'
|
314
|
+
expect(parent.status).to eq 'queued'
|
315
|
+
end
|
316
|
+
|
357
317
|
it 'does not run job if no data sent' do
|
358
318
|
expect(@port1.job).not_to receive(:run)
|
359
319
|
@out1.connect_to @port1
|
360
320
|
end
|
361
321
|
|
362
|
-
it 'does not run job for memory port' do
|
363
|
-
expect(@memory.job).not_to receive(:run)
|
364
|
-
@out1.write true
|
365
|
-
@out1.connect_to @memory
|
366
|
-
end
|
367
|
-
|
368
322
|
it 'logs data' do
|
369
323
|
now = Time.now
|
370
324
|
allow(Time).to receive(:now) { now }
|
@@ -377,21 +331,21 @@ describe SideJob::Port do
|
|
377
331
|
'write' => [{'job' => @job.id, 'inport' => 'port1', 'data' => [1,[2,3]]}] }])
|
378
332
|
end
|
379
333
|
|
380
|
-
it 'can
|
334
|
+
it 'can use SideJob.log_context to specify additional metadata' do
|
381
335
|
now = Time.now
|
382
336
|
allow(Time).to receive(:now) { now }
|
383
|
-
job2 = SideJob.queue('testq', 'TestWorker')
|
384
337
|
@out1.write 1
|
385
338
|
@out1.write [2,3]
|
386
339
|
SideJob.logs(clear: true)
|
387
|
-
|
340
|
+
SideJob.log_context(user: 'test') do
|
341
|
+
@out1.connect_to(@port1)
|
342
|
+
end
|
388
343
|
expect(SideJob.logs).to eq([{'timestamp' => SideJob.timestamp, 'user' => 'test',
|
389
344
|
'read' => [{'job' => @job.id, 'outport' => 'out1', 'data' => [1,[2,3]]}],
|
390
345
|
'write' => [{'job' => @job.id, 'inport' => 'port1', 'data' => [1,[2,3]]}] }])
|
391
346
|
end
|
392
347
|
|
393
348
|
it 'does not log if no data on port' do
|
394
|
-
job2 = SideJob.queue('testq', 'TestWorker')
|
395
349
|
@out1.connect_to(@port1)
|
396
350
|
expect(SideJob.logs).to eq([])
|
397
351
|
end
|
@@ -419,11 +373,7 @@ describe SideJob::Port do
|
|
419
373
|
@defaults.each do |port|
|
420
374
|
expect(port.entries).to eq []
|
421
375
|
port.write 'mydata'
|
422
|
-
|
423
|
-
expect(port.entries).to eq []
|
424
|
-
else
|
425
|
-
expect(port.entries).to eq ['mydata']
|
426
|
-
end
|
376
|
+
expect(port.entries).to eq ['mydata']
|
427
377
|
end
|
428
378
|
end
|
429
379
|
end
|
@@ -449,4 +399,68 @@ describe SideJob::Port do
|
|
449
399
|
expect(h[@port1]).to be(3)
|
450
400
|
end
|
451
401
|
end
|
402
|
+
|
403
|
+
describe '.log_group' do
|
404
|
+
before do
|
405
|
+
now = Time.now
|
406
|
+
allow(Time).to receive(:now) { now }
|
407
|
+
end
|
408
|
+
|
409
|
+
it 'does not log anything if no port operations occur within the block' do
|
410
|
+
SideJob::Port.log_group {}
|
411
|
+
expect(SideJob.logs.length).to eq 0
|
412
|
+
end
|
413
|
+
|
414
|
+
it 'groups all port logs within the block' do
|
415
|
+
SideJob::Port.log_group do
|
416
|
+
@port1.write 'abc'
|
417
|
+
@port1.read
|
418
|
+
@port1.write 'def'
|
419
|
+
@out1.write 'xyz'
|
420
|
+
end
|
421
|
+
expect(SideJob.logs).to eq [{'timestamp' => SideJob.timestamp,
|
422
|
+
'read' => [{'job' => @port1.job.id, 'inport' => 'port1', 'data' => ['abc']}],
|
423
|
+
'write' => [{'job' => @port1.job.id, 'inport' => 'port1', 'data' => ['abc', 'def']}, {'job' => @out1.job.id, 'outport' => 'out1', 'data' => ['xyz']} ]}]
|
424
|
+
end
|
425
|
+
|
426
|
+
it 'does not write out log until the end of outermost group' do
|
427
|
+
SideJob::Port.log_group do
|
428
|
+
@port1.write 'hello'
|
429
|
+
SideJob::Port.log_group do
|
430
|
+
@port1.write 2
|
431
|
+
end
|
432
|
+
expect(SideJob.logs.length).to eq 0
|
433
|
+
end
|
434
|
+
expect(SideJob.logs).to eq [{'timestamp' => SideJob.timestamp,
|
435
|
+
'read' => [],
|
436
|
+
'write' => [{'job' => @port1.job.id, 'inport' => 'port1', 'data' => ['hello', 2]}]}]
|
437
|
+
end
|
438
|
+
|
439
|
+
it 'works with SideJob.log_context' do
|
440
|
+
SideJob.log_context(user: 'foo') do
|
441
|
+
SideJob::Port.log_group do
|
442
|
+
@port1.write 'abc'
|
443
|
+
@port1.read
|
444
|
+
end
|
445
|
+
end
|
446
|
+
expect(SideJob.logs).to eq [{'timestamp' => SideJob.timestamp, 'user' => 'foo',
|
447
|
+
'read' => [{'job' => @port1.job.id, 'inport' => 'port1', 'data' => ['abc']}],
|
448
|
+
'write' => [{'job' => @port1.job.id, 'inport' => 'port1', 'data' => ['abc']}]}]
|
449
|
+
end
|
450
|
+
|
451
|
+
it 'logs correctly even if data is changed' do
|
452
|
+
data = {'x' => [1,2]}
|
453
|
+
SideJob::Port.log_group do
|
454
|
+
@port1.write data
|
455
|
+
expect(@port1.read).to eq data
|
456
|
+
data['x'].push 3
|
457
|
+
@port1.write data
|
458
|
+
expect(@port1.read).to eq data
|
459
|
+
end
|
460
|
+
expect(SideJob.logs).to eq [{'timestamp' => SideJob.timestamp,
|
461
|
+
'read' => [{'job' => @port1.job.id, 'inport' => 'port1', 'data' => [{'x' => [1,2]},{'x' => [1,2,3]}]}],
|
462
|
+
'write' => [{'job' => @port1.job.id, 'inport' => 'port1', 'data' => [{'x' => [1,2]},{'x' => [1,2,3]}]}],
|
463
|
+
}]
|
464
|
+
end
|
465
|
+
end
|
452
466
|
end
|