rufus-scheduler 3.0.8 → 3.2.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.
data/spec/job_spec.rb DELETED
@@ -1,631 +0,0 @@
1
-
2
- #
3
- # Specifying rufus-scheduler
4
- #
5
- # Wed Apr 17 06:00:59 JST 2013
6
- #
7
-
8
- require 'spec_helper'
9
-
10
-
11
- describe Rufus::Scheduler::Job do
12
-
13
- # specify behaviours common to all job classes
14
-
15
- before :each do
16
-
17
- @taoe = Thread.abort_on_exception
18
- Thread.abort_on_exception = false
19
-
20
- @ose = $stderr
21
- $stderr = StringIO.new
22
-
23
- @scheduler = Rufus::Scheduler.new
24
- end
25
-
26
- after :each do
27
-
28
- @scheduler.shutdown
29
-
30
- Thread.abort_on_exception = @taoe
31
-
32
- $stderr = @ose
33
- end
34
-
35
- describe '#last_time' do
36
-
37
- it 'returns nil if the job never fired' do
38
-
39
- job = @scheduler.schedule_in '10d' do; end
40
-
41
- expect(job.last_time).to eq(nil)
42
- end
43
-
44
- it 'returns the last time the job fired' do
45
-
46
- job = @scheduler.schedule_in '0s' do; end
47
-
48
- sleep 0.4
49
-
50
- expect(job.last_time).not_to eq(nil)
51
- end
52
- end
53
-
54
- describe '#threads' do
55
-
56
- it 'returns an empty list when the job is not running' do
57
-
58
- job = @scheduler.in('1d', :job => true) {}
59
-
60
- expect(job.threads.size).to eq(0)
61
- end
62
-
63
- it 'returns an empty list after the job terminated' do
64
-
65
- job = @scheduler.in('0s', :job => true) {}
66
-
67
- sleep 0.8
68
-
69
- expect(job.threads.size).to eq(0)
70
- end
71
-
72
- it 'lists the threads the job currently runs in' do
73
-
74
- job =
75
- @scheduler.schedule_in('0s') do
76
- sleep(1)
77
- end
78
-
79
- sleep 0.4
80
-
81
- expect(job.threads.size).to eq(1)
82
-
83
- t = job.threads.first
84
- expect(t[:rufus_scheduler_job]).to eq(job)
85
- end
86
- end
87
-
88
- describe '#kill' do
89
-
90
- it 'has no effect if the job is not running' do
91
-
92
- job = @scheduler.schedule_in '10d' do; end
93
-
94
- tls = Thread.list.size
95
-
96
- job.kill
97
-
98
- expect(Thread.list.size).to eq(tls)
99
- end
100
-
101
- it 'makes the threads vacant' do
102
-
103
- counter = 0
104
-
105
- job =
106
- @scheduler.schedule_in '0s' do
107
- sleep 2
108
- counter = counter + 1
109
- end
110
-
111
- sleep 1
112
-
113
- v0 = @scheduler.work_threads(:vacant).size
114
- a0 = @scheduler.work_threads(:active).size
115
-
116
- job.kill
117
-
118
- sleep 2
119
-
120
- v1 = @scheduler.work_threads(:vacant).size
121
- a1 = @scheduler.work_threads(:active).size
122
-
123
- expect(counter).to eq(0)
124
-
125
- expect(v0).to eq(0)
126
- expect(a0).to eq(1)
127
-
128
- expect(v1).to eq(1)
129
- expect(a1).to eq(0)
130
- end
131
- end
132
-
133
- describe '#running?' do
134
-
135
- it 'returns false when the job is not running in any thread' do
136
-
137
- job = @scheduler.in('1d', :job => true) {}
138
-
139
- expect(job.running?).to eq(false)
140
- end
141
-
142
- it 'returns true when the job is running in at least one thread' do
143
-
144
- job = @scheduler.in('0s', :job => true) { sleep(1) }
145
-
146
- sleep 0.4
147
-
148
- expect(job.running?).to eq(true)
149
- end
150
- end
151
-
152
- describe '#scheduled?' do
153
-
154
- it 'returns true when the job is scheduled' do
155
-
156
- job = @scheduler.schedule_in('1d') {}
157
-
158
- expect(job.scheduled?).to eq(true)
159
- end
160
-
161
- it 'returns false when the job is not scheduled' do
162
-
163
- job = @scheduler.schedule_in('0.1s') {}
164
-
165
- sleep 0.4
166
-
167
- expect(job.scheduled?).to eq(false)
168
- end
169
-
170
- it 'returns true for repeat jobs that are running' do
171
-
172
- job = @scheduler.schedule_interval('0.4s') { sleep(10) }
173
-
174
- sleep 1
175
-
176
- expect(job.running?).to eq(true)
177
- expect(job.scheduled?).to eq(true)
178
- end
179
- end
180
-
181
- describe '#call' do
182
-
183
- it 'calls the job (like it were a proc)' do
184
-
185
- counter = 0
186
-
187
- job =
188
- @scheduler.schedule_in('0.5s') do
189
- counter = counter + 1
190
- end
191
- job.call
192
-
193
- sleep 0.8
194
-
195
- expect(counter).to eq(2)
196
- end
197
- end
198
-
199
- describe '#call(true)' do
200
-
201
- it 'calls the job and let the scheduler handle errors' do
202
-
203
- $err = nil
204
-
205
- def @scheduler.on_error(job, err)
206
- $err = "#{job.class} #{job.original} #{err.message}"
207
- rescue
208
- p $!
209
- end
210
-
211
- job =
212
- @scheduler.schedule_in('1d') do
213
- fail 'again'
214
- end
215
-
216
- job.call(true)
217
-
218
- expect($err).to eq('Rufus::Scheduler::InJob 1d again')
219
- end
220
- end
221
-
222
- describe '#call(false)' do
223
-
224
- it 'calls the job and let errors slip through' do
225
-
226
- job =
227
- @scheduler.schedule_in('1d') do
228
- fail 'fast'
229
- end
230
-
231
- begin
232
-
233
- #job.call(false)
234
- job.call # false is the default
235
-
236
- expect(false).to eq(true)
237
-
238
- rescue => ex
239
-
240
- expect(ex.message).to eq('fast')
241
- end
242
- end
243
- end
244
-
245
- context 'job-local variables' do
246
-
247
- describe '#[]=' do
248
-
249
- it 'sets a job-local variable' do
250
-
251
- job =
252
- @scheduler.schedule_every '1s' do |job|
253
- job[:counter] ||= 0
254
- job[:counter] += 1
255
- end
256
-
257
- sleep 3
258
-
259
- expect(job[:counter]).to be > 1
260
- end
261
- end
262
-
263
- describe '#[]' do
264
-
265
- it 'returns nil if there is no such entry' do
266
-
267
- job = @scheduler.schedule_in '1s' do; end
268
-
269
- expect(job[:nada]).to eq(nil)
270
- end
271
-
272
- it 'returns the value of a job-local variable' do
273
-
274
- job = @scheduler.schedule_in '1s' do; end
275
- job[:x] = :y
276
-
277
- expect(job[:x]).to eq(:y)
278
- end
279
- end
280
-
281
- describe '#key?' do
282
-
283
- it 'returns true if there is an entry with the given key' do
284
-
285
- job = @scheduler.schedule_in '1s' do; end
286
- job[:x] = :y
287
-
288
- expect(job.key?(:x)).to eq(true)
289
- end
290
- end
291
-
292
- describe '#keys' do
293
-
294
- it 'returns the array of keys of the job-local variables' do
295
-
296
- job = @scheduler.schedule_in '1s' do; end
297
- job[:x] = :y
298
- job['hello'] = :z
299
- job[123] = {}
300
-
301
- expect(job.keys.sort_by { |k| k.to_s }).to eq([ 123, 'hello', :x ])
302
- end
303
- end
304
- end
305
-
306
- context ':tag / :tags => [ t0, t1 ]' do
307
-
308
- it 'accepts one tag' do
309
-
310
- job = @scheduler.in '10d', :job => true, :tag => 't0' do; end
311
-
312
- expect(job.tags).to eq(%w[ t0 ])
313
- end
314
-
315
- it 'accepts an array of tags' do
316
-
317
- job = @scheduler.in '10d', :job => true, :tag => %w[ t0 t1 ] do; end
318
-
319
- expect(job.tags).to eq(%w[ t0 t1 ])
320
- end
321
-
322
- it 'turns tags into strings' do
323
-
324
- job = @scheduler.in '10d', :job => true, :tags => [ 1, 2 ] do; end
325
-
326
- expect(job.tags).to eq(%w[ 1 2 ])
327
- end
328
- end
329
-
330
- context ':blocking => true' do
331
-
332
- it 'runs the job in the same thread as the scheduler thread' do
333
-
334
- job =
335
- @scheduler.in('0s', :job => true, :blocking => true) do
336
- sleep(1)
337
- end
338
-
339
- sleep 0.4
340
-
341
- expect(job.threads.first).to eq(@scheduler.thread)
342
-
343
- sleep 1.4
344
-
345
- expect(job.threads.size).to eq(0)
346
- end
347
- end
348
-
349
- context 'default one thread per job behaviour' do
350
-
351
- it 'runs the job in a dedicated thread' do
352
-
353
- job =
354
- @scheduler.in('0s', :job => true) do
355
- sleep(1)
356
- end
357
-
358
- sleep 0.4
359
-
360
- expect(job.threads.first).not_to eq(@scheduler.thread)
361
-
362
- sleep 1.4
363
-
364
- expect(job.threads.size).to eq(0)
365
- end
366
- end
367
-
368
- context ':allow_overlapping / :allow_overlap / :overlap' do
369
-
370
- context 'default (:overlap => true)' do
371
-
372
- it 'lets a job overlap itself' do
373
-
374
- job =
375
- @scheduler.every('0.3', :job => true) do
376
- sleep(5)
377
- end
378
-
379
- sleep 3
380
-
381
- expect(job.threads.size).to be > 1
382
- end
383
- end
384
-
385
- context 'when :overlap => false' do
386
-
387
- it 'prevents a job from overlapping itself' do
388
-
389
- job =
390
- @scheduler.every('0.3', :job => true, :overlap => false) do
391
- sleep(5)
392
- end
393
-
394
- sleep 3
395
-
396
- expect(job.threads.size).to eq(1)
397
- end
398
- end
399
- end
400
-
401
- context ':mutex' do
402
-
403
- context ':mutex => "mutex_name"' do
404
-
405
- it 'prevents concurrent executions' do
406
-
407
- j0 =
408
- @scheduler.in('0s', :job => true, :mutex => 'vladivostok') do
409
- sleep(3)
410
- end
411
- j1 =
412
- @scheduler.in('0s', :job => true, :mutex => 'vladivostok') do
413
- sleep(3)
414
- end
415
-
416
- sleep 0.7
417
-
418
- if j0.threads.any?
419
- expect(j0.threads.size).to eq(1)
420
- expect(j1.threads.size).to eq(0)
421
- else
422
- expect(j0.threads.size).to eq(0)
423
- expect(j1.threads.size).to eq(1)
424
- end
425
-
426
- expect(@scheduler.mutexes.keys).to eq(%w[ vladivostok ])
427
- end
428
- end
429
-
430
- context ':mutex => mutex_instance' do
431
-
432
- it 'prevents concurrent executions' do
433
-
434
- m = Mutex.new
435
-
436
- j0 = @scheduler.in('0s', :job => true, :mutex => m) { sleep(3) }
437
- j1 = @scheduler.in('0s', :job => true, :mutex => m) { sleep(3) }
438
-
439
- sleep 0.7
440
-
441
- if j0.threads.any?
442
- expect(j0.threads.size).to eq(1)
443
- expect(j1.threads.size).to eq(0)
444
- else
445
- expect(j0.threads.size).to eq(0)
446
- expect(j1.threads.size).to eq(1)
447
- end
448
-
449
- expect(@scheduler.mutexes.keys).to eq([])
450
- end
451
- end
452
-
453
- context ':mutex => [ array_of_mutex_names_or_instances ]' do
454
-
455
- it 'prevents concurrent executions' do
456
-
457
- j0 =
458
- @scheduler.in('0s', :job => true, :mutex => %w[ a b ]) do
459
- sleep(3)
460
- end
461
- j1 =
462
- @scheduler.in('0s', :job => true, :mutex => %w[ a b ]) do
463
- sleep(3)
464
- end
465
-
466
- sleep 0.7
467
-
468
- if j0.threads.any?
469
- expect(j0.threads.size).to eq(1)
470
- expect(j1.threads.size).to eq(0)
471
- else
472
- expect(j0.threads.size).to eq(0)
473
- expect(j1.threads.size).to eq(1)
474
- end
475
-
476
- expect(@scheduler.mutexes.keys.sort).to eq(%w[ a b ])
477
- end
478
- end
479
- end
480
-
481
- context ':timeout => duration_or_point_in_time' do
482
-
483
- it 'interrupts the job it is stashed to (duration)' do
484
-
485
- counter = 0
486
- toe = nil
487
-
488
- job =
489
- @scheduler.schedule_in '0s', :timeout => '1s' do
490
- begin
491
- counter = counter + 1
492
- sleep 1.5
493
- counter = counter + 1
494
- rescue Rufus::Scheduler::TimeoutError => e
495
- toe = e
496
- end
497
- end
498
-
499
- sleep(3)
500
-
501
- expect(counter).to eq(1)
502
- expect(toe.class).to eq(Rufus::Scheduler::TimeoutError)
503
- end
504
-
505
- it 'interrupts the job it is stashed to (point in time)' do
506
-
507
- counter = 0
508
-
509
- job =
510
- @scheduler.schedule_in '0s', :timeout => Time.now + 1 do
511
- begin
512
- counter = counter + 1
513
- sleep 1.5
514
- counter = counter + 1
515
- rescue Rufus::Scheduler::TimeoutError => e
516
- end
517
- end
518
-
519
- sleep(3)
520
-
521
- expect(counter).to eq(1)
522
- end
523
-
524
- it 'starts timing when the job enters successfully all its mutexes' do
525
-
526
- t0, t1, t2 = nil
527
-
528
- @scheduler.schedule_in '0s', :mutex => 'a' do
529
- sleep 1
530
- t0 = Time.now
531
- end
532
-
533
- job =
534
- @scheduler.schedule_in '0.5s', :mutex => 'a', :timeout => '1s' do
535
- begin
536
- t1 = Time.now
537
- sleep 2
538
- rescue Rufus::Scheduler::TimeoutError => e
539
- t2 = Time.now
540
- end
541
- end
542
-
543
- sleep 3
544
-
545
- expect(t0).to be <= t1
546
-
547
- d = t2 - t1
548
- expect(d).to be >= 1.0
549
- expect(d).to be < 1.5
550
- end
551
-
552
- it 'emits the timeout information to $stderr (default #on_error)' do
553
-
554
- @scheduler.every('1s', :timeout => '0.5s') do
555
- sleep 0.9
556
- end
557
-
558
- sleep 2
559
-
560
- expect($stderr.string).to match(/Rufus::Scheduler::TimeoutError/)
561
- end
562
-
563
- it 'does not prevent a repeat job from recurring' do
564
-
565
- counter = 0
566
-
567
- @scheduler.every('1s', :timeout => '0.5s') do
568
- counter = counter + 1
569
- sleep 0.9
570
- end
571
-
572
- sleep 3
573
-
574
- expect(counter).to be > 1
575
- end
576
- end
577
-
578
- context 'work time' do
579
-
580
- describe '#last_work_time' do
581
-
582
- it 'starts at 0' do
583
-
584
- job = @scheduler.schedule_every '5m' do; end
585
-
586
- expect(job.last_work_time).to eq(0.0)
587
- end
588
-
589
- it 'keeps track of how long the work was upon last trigger' do
590
-
591
- job =
592
- @scheduler.schedule_in '0.5s' do
593
- sleep 0.7
594
- end
595
-
596
- sleep 2
597
-
598
- expect(job.last_work_time).to be >= 0.7
599
- expect(job.last_work_time).to be < 0.8
600
- end
601
- end
602
-
603
- describe '#mean_work_time' do
604
-
605
- it 'starts at 0' do
606
-
607
- job = @scheduler.schedule_every '5m' do; end
608
-
609
- expect(job.mean_work_time).to eq(0.0)
610
- end
611
-
612
- it 'gathers work times and computes the mean' do
613
-
614
- job =
615
- @scheduler.schedule_every '0.5s' do |j|
616
- #p j.last_work_time
617
- #p j.mean_work_time
618
- sleep 0.01 * (j.count + 1)
619
- end
620
-
621
- sleep 4.6
622
-
623
- expect(job.last_work_time).to be >= 0.08
624
- expect(job.last_work_time).to be < 0.099
625
- expect(job.mean_work_time).to be > 0.05
626
- expect(job.mean_work_time).to be < 0.06
627
- end
628
- end
629
- end
630
- end
631
-
@@ -1,61 +0,0 @@
1
-
2
- #
3
- # Specifying rufus-scheduler
4
- #
5
- # Tue Aug 13 05:58:48 JST 2013
6
- #
7
-
8
- require 'spec_helper'
9
-
10
-
11
- describe Rufus::Scheduler do
12
-
13
- after :each do
14
-
15
- FileUtils.rm_f('.rufus-scheduler.lock')
16
- FileUtils.rm_f('lock.txt')
17
- end
18
-
19
- context ':lockfile => ".rufus-scheduler.lock"' do
20
-
21
- it 'writes down a .rufus-scheduler.lock file' do
22
-
23
- s = Rufus::Scheduler.new :lockfile => '.rufus-scheduler.lock'
24
-
25
- line = File.read('.rufus-scheduler.lock')
26
-
27
- #p line
28
- expect(line).to match(/pid: #{$$}/)
29
- end
30
-
31
- it '"flocks" the lock file' do
32
-
33
- s = Rufus::Scheduler.new :lockfile => '.rufus-scheduler.lock'
34
-
35
- f = File.new('.rufus-scheduler.lock', 'a')
36
-
37
- expect(f.flock(File::LOCK_NB | File::LOCK_EX)).to eq(false)
38
- end
39
-
40
- it 'prevents newer schedulers from starting' do
41
-
42
- s0 = Rufus::Scheduler.new :lockfile => '.rufus-scheduler.lock'
43
- s1 = Rufus::Scheduler.new :lockfile => '.rufus-scheduler.lock'
44
-
45
- expect(s0.started_at).not_to eq(nil)
46
- expect(s1.started_at).to eq(nil)
47
- end
48
-
49
- it 'releases the lockfile when shutting down' do
50
-
51
- s = Rufus::Scheduler.new :lockfile => '.rufus-scheduler.lock'
52
-
53
- s.shutdown(:kill)
54
-
55
- f = File.new('.rufus-scheduler.lock', 'a')
56
-
57
- expect(f.flock(File::LOCK_NB | File::LOCK_EX)).to eq(0)
58
- end
59
- end
60
- end
61
-