rufus-scheduler 2.0.24 → 3.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (63) hide show
  1. data/CHANGELOG.txt +76 -0
  2. data/CREDITS.txt +23 -0
  3. data/LICENSE.txt +1 -1
  4. data/README.md +1439 -0
  5. data/Rakefile +1 -5
  6. data/TODO.txt +149 -55
  7. data/lib/rufus/{sc → scheduler}/cronline.rb +167 -53
  8. data/lib/rufus/scheduler/job_array.rb +92 -0
  9. data/lib/rufus/scheduler/jobs.rb +633 -0
  10. data/lib/rufus/scheduler/locks.rb +95 -0
  11. data/lib/rufus/scheduler/util.rb +306 -0
  12. data/lib/rufus/scheduler/zones.rb +174 -0
  13. data/lib/rufus/scheduler/zotime.rb +154 -0
  14. data/lib/rufus/scheduler.rb +608 -27
  15. data/rufus-scheduler.gemspec +6 -4
  16. data/spec/basics_spec.rb +54 -0
  17. data/spec/cronline_spec.rb +479 -152
  18. data/spec/error_spec.rb +139 -0
  19. data/spec/job_array_spec.rb +39 -0
  20. data/spec/job_at_spec.rb +58 -0
  21. data/spec/job_cron_spec.rb +128 -0
  22. data/spec/job_every_spec.rb +104 -0
  23. data/spec/job_in_spec.rb +20 -0
  24. data/spec/job_interval_spec.rb +68 -0
  25. data/spec/job_repeat_spec.rb +357 -0
  26. data/spec/job_spec.rb +498 -109
  27. data/spec/lock_custom_spec.rb +47 -0
  28. data/spec/lock_flock_spec.rb +47 -0
  29. data/spec/lock_lockfile_spec.rb +61 -0
  30. data/spec/lock_spec.rb +59 -0
  31. data/spec/parse_spec.rb +263 -0
  32. data/spec/schedule_at_spec.rb +158 -0
  33. data/spec/schedule_cron_spec.rb +66 -0
  34. data/spec/schedule_every_spec.rb +109 -0
  35. data/spec/schedule_in_spec.rb +80 -0
  36. data/spec/schedule_interval_spec.rb +128 -0
  37. data/spec/scheduler_spec.rb +928 -124
  38. data/spec/spec_helper.rb +126 -0
  39. data/spec/threads_spec.rb +96 -0
  40. data/spec/zotime_spec.rb +396 -0
  41. metadata +56 -33
  42. data/README.rdoc +0 -661
  43. data/lib/rufus/otime.rb +0 -3
  44. data/lib/rufus/sc/jobqueues.rb +0 -160
  45. data/lib/rufus/sc/jobs.rb +0 -471
  46. data/lib/rufus/sc/rtime.rb +0 -363
  47. data/lib/rufus/sc/scheduler.rb +0 -636
  48. data/lib/rufus/sc/version.rb +0 -32
  49. data/spec/at_in_spec.rb +0 -47
  50. data/spec/at_spec.rb +0 -125
  51. data/spec/blocking_spec.rb +0 -64
  52. data/spec/cron_spec.rb +0 -134
  53. data/spec/every_spec.rb +0 -304
  54. data/spec/exception_spec.rb +0 -113
  55. data/spec/in_spec.rb +0 -150
  56. data/spec/mutex_spec.rb +0 -159
  57. data/spec/rtime_spec.rb +0 -137
  58. data/spec/schedulable_spec.rb +0 -97
  59. data/spec/spec_base.rb +0 -87
  60. data/spec/stress_schedule_unschedule_spec.rb +0 -159
  61. data/spec/timeout_spec.rb +0 -148
  62. data/test/kjw.rb +0 -113
  63. data/test/t.rb +0 -20
@@ -0,0 +1,139 @@
1
+
2
+ #
3
+ # Specifying rufus-scheduler
4
+ #
5
+ # Fri Aug 9 07:10:18 JST 2013
6
+ #
7
+
8
+ require 'spec_helper'
9
+
10
+
11
+ describe Rufus::Scheduler do
12
+
13
+ before :each do
14
+
15
+ @taoe = Thread.abort_on_exception
16
+ Thread.abort_on_exception = false
17
+
18
+ @ose = $stderr
19
+ $stderr = StringIO.new
20
+
21
+ @scheduler = Rufus::Scheduler.new
22
+ end
23
+
24
+ after :each do
25
+
26
+ @scheduler.shutdown
27
+
28
+ Thread.abort_on_exception = @taoe
29
+
30
+ $stderr = @ose
31
+ end
32
+
33
+ context 'error in block' do
34
+
35
+ it 'intercepts the error and describes it on $stderr' do
36
+
37
+ counter = 0
38
+
39
+ @scheduler.every('0.5s') do
40
+ counter += 1
41
+ fail 'argh'
42
+ end
43
+
44
+ sleep 2
45
+
46
+ expect(counter).to be > 2
47
+ expect($stderr.string).to match(/argh/)
48
+ end
49
+ end
50
+
51
+ context 'error in callable' do
52
+
53
+ class MyFailingHandler
54
+ attr_reader :counter
55
+ def initialize
56
+ @counter = 0
57
+ end
58
+ def call(job, time)
59
+ @counter = @counter + 1
60
+ fail 'ouch'
61
+ end
62
+ end
63
+
64
+ it 'intercepts the error and describes it on $stderr' do
65
+
66
+ mfh = MyFailingHandler.new
67
+
68
+ @scheduler.every('0.5s', mfh)
69
+
70
+ sleep 2
71
+
72
+ expect(mfh.counter).to be > 2
73
+ expect($stderr.string).to match(/ouch/)
74
+ end
75
+ end
76
+
77
+ context 'Rufus::Scheduler#stderr=' do
78
+
79
+ it 'lets divert error information to custom files' do
80
+
81
+ @scheduler.stderr = StringIO.new
82
+
83
+ @scheduler.in('0s') do
84
+ fail 'miserably'
85
+ end
86
+
87
+ sleep 0.5
88
+
89
+ expect(@scheduler.stderr.string).to match(/intercepted an error/)
90
+ expect(@scheduler.stderr.string).to match(/miserably/)
91
+ end
92
+ end
93
+
94
+ context 'error information' do
95
+
96
+ it 'contains information about the error, the job and the scheduler' do
97
+
98
+ @scheduler.stderr = StringIO.new
99
+
100
+ @scheduler.in('0s') do
101
+ fail 'miserably'
102
+ end
103
+
104
+ sleep 0.5
105
+
106
+ s = @scheduler.stderr.string
107
+ #puts s
108
+
109
+ expect(s).to match(/ENV\['TZ'\]:/)
110
+ expect(s).to match(/down\?: false/)
111
+ expect(s).to match(/work_threads: 1/)
112
+ expect(s).to match(/running_jobs: 1/)
113
+ expect(s).to match(/uptime: \d/)
114
+ end
115
+ end
116
+
117
+ context 'Rufus::Scheduler#on_error(&block)' do
118
+
119
+ it 'intercepts all StandardError instances' do
120
+
121
+ $message = nil
122
+
123
+ def @scheduler.on_error(job, err)
124
+ $message = "#{job.class} #{job.original} #{err.message}"
125
+ rescue
126
+ p $!
127
+ end
128
+
129
+ @scheduler.in('0s') do
130
+ fail 'miserably'
131
+ end
132
+
133
+ sleep 0.5
134
+
135
+ expect($message).to eq('Rufus::Scheduler::InJob 0s miserably')
136
+ end
137
+ end
138
+ end
139
+
@@ -0,0 +1,39 @@
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::JobArray do
12
+
13
+ class DummyJob < Struct.new(:id, :next_time); end
14
+
15
+ before(:each) do
16
+ @array = Rufus::Scheduler::JobArray.new
17
+ end
18
+
19
+ describe '#push' do
20
+
21
+ it 'pushes jobs' do
22
+
23
+ @array.push(DummyJob.new('a', Time.local(0)))
24
+
25
+ expect(@array.to_a.collect(&:id)).to eq(%w[ a ])
26
+ end
27
+
28
+ it 'pushes and remove duplicates' do
29
+
30
+ j = DummyJob.new('a', Time.local(0))
31
+
32
+ @array.push(j)
33
+ @array.push(j)
34
+
35
+ expect(@array.to_a.collect(&:id)).to eq(%w[ a ])
36
+ end
37
+ end
38
+ end
39
+
@@ -0,0 +1,58 @@
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::AtJob do
12
+
13
+ before :each do
14
+ @scheduler = Rufus::Scheduler.new
15
+ end
16
+ after :each do
17
+ @scheduler.shutdown
18
+ end
19
+
20
+ describe '#unschedule' do
21
+
22
+ it 'unschedules the job' do
23
+
24
+ job = @scheduler.at(Time.now + 3600, :job => true) do
25
+ end
26
+
27
+ job.unschedule
28
+
29
+ sleep 0.4
30
+
31
+ expect(@scheduler.jobs.size).to eq(0)
32
+ end
33
+ end
34
+
35
+ describe '#scheduled_at' do
36
+
37
+ it 'returns the Time at which the job got scheduled' do
38
+
39
+ job = @scheduler.schedule_at((t = Time.now) + 3600) {}
40
+
41
+ expect(job.scheduled_at.to_i).to be >= t.to_i - 1
42
+ expect(job.scheduled_at.to_i).to be <= t.to_i + 1
43
+ end
44
+ end
45
+
46
+ describe '#time' do
47
+
48
+ it 'returns the time at which the job will trigger' do
49
+
50
+ t = Time.now + 3600
51
+
52
+ job = @scheduler.schedule_at t do; end
53
+
54
+ expect(job.time).to eq(t)
55
+ end
56
+ end
57
+ end
58
+
@@ -0,0 +1,128 @@
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::CronJob do
12
+
13
+ before :each do
14
+ @scheduler = Rufus::Scheduler.new
15
+ end
16
+ after :each do
17
+ @scheduler.shutdown
18
+ end
19
+
20
+ context 'normal' do
21
+
22
+ it 'triggers near the zero second' do
23
+
24
+ job = @scheduler.schedule_cron '* * * * *' do; end
25
+
26
+ sleep_until_next_minute
27
+
28
+ expect(job.last_time.to_i % 10).to eq(0)
29
+ end
30
+ end
31
+
32
+ #context 'sub-minute' do
33
+ #
34
+ # it 'triggers near the zero second' do
35
+ #
36
+ # job = @scheduler.schedule_cron '* * * * * *' do; end
37
+ #
38
+ # sleep 1.5
39
+ #
40
+ # p job.last_time
41
+ # p job.last_time.to_f
42
+ # end
43
+ #end
44
+
45
+ context 'first_at/in' do
46
+
47
+ it 'does not trigger before first_at is reached' do
48
+
49
+ t = Time.now
50
+
51
+ job =
52
+ @scheduler.schedule_cron '* * * * * *', :first_in => '3s' do
53
+ triggered = Time.now
54
+ end
55
+
56
+ sleep 1
57
+
58
+ #p [ t, t.to_f ]
59
+ #p [ job.last_time, job.last_time.to_f ]
60
+ #p [ job.first_at, job.first_at.to_f ]
61
+
62
+ expect(job.first_at).to be_within_1s_of(t + 3)
63
+ expect(job.last_time).to eq(nil)
64
+ end
65
+
66
+ it 'triggers for the first time at first_at' do
67
+
68
+ first_time = nil
69
+ t = Time.now
70
+
71
+ job = @scheduler.schedule_cron '* * * * * *', :first_in => '3s' do
72
+ first_time ||= Time.now
73
+ end
74
+ sleep 4.5
75
+
76
+ expect(job.first_at).to be_within_1s_of(t + 3)
77
+ expect(first_time).to be_within_1s_of(job.first_at)
78
+ end
79
+ end
80
+
81
+ context 'scheduling the cron itself' do
82
+
83
+ # for https://github.com/jmettraux/rufus-scheduler/issues/95
84
+ #
85
+ # schedule_cron takes more than 30 seconds, blocking...
86
+ #
87
+ it 'does not sit scheduling and blocking...' do
88
+
89
+ n = Time.now
90
+ first = nil
91
+
92
+ job = @scheduler.schedule_cron '*/2 * * * * *' do
93
+ first ||= Time.now
94
+ end
95
+
96
+ expect(Time.now - n).to be < 1.0
97
+
98
+ loop do
99
+ next unless first
100
+ expect(first - n).to be < 4.0
101
+ break
102
+ end
103
+ end
104
+ end
105
+
106
+ describe '.next_time' do
107
+
108
+ it 'returns the next trigger time' do
109
+
110
+ n = Time.now
111
+ nt = Time.parse("#{n.year}-#{n.month + 1}-01")
112
+
113
+ expect(
114
+ @scheduler.schedule_cron('* * 1 * *', lambda {}).next_time
115
+ ).to eq(nt)
116
+ end
117
+
118
+ it 'returns the next trigger time (first_at => Time)' do
119
+
120
+ ft = Time.parse('2100-12-31')
121
+
122
+ job = @scheduler.schedule_cron('* * 1 * *', :first_at => ft) {}
123
+
124
+ expect(job.next_time).to eq(ft)
125
+ end
126
+ end
127
+ end
128
+
@@ -0,0 +1,104 @@
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::EveryJob do
12
+
13
+ before :each do
14
+ @scheduler = Rufus::Scheduler.new
15
+ end
16
+ after :each do
17
+ @scheduler.shutdown
18
+ end
19
+
20
+ it 'triggers as expected' do
21
+
22
+ counter = 0
23
+
24
+ @scheduler.every '1s' do
25
+ counter = counter + 1
26
+ end
27
+
28
+ sleep 3.5
29
+
30
+ expect([ 2, 3 ]).to include(counter)
31
+ end
32
+
33
+ it 'lets its @next_time change in-flight' do
34
+
35
+ times = []
36
+
37
+ @scheduler.every '1s' do |job|
38
+ times << Time.now
39
+ job.next_time = Time.now + 3 if times.count == 2
40
+ end
41
+
42
+ sleep 0.3 while times.count < 3
43
+
44
+ #p [ times[1] - times[0], times[2] - times[1] ]
45
+
46
+ expect(times[1] - times[0]).to be > 1.0
47
+ expect(times[1] - times[0]).to be < 1.4
48
+ expect(times[2] - times[1]).to be > 3.0
49
+ expect(times[2] - times[1]).to be < 3.4
50
+ end
51
+
52
+ context 'summer time' do
53
+
54
+ it 'triggers correctly through a DST transition' do
55
+
56
+ job = Rufus::Scheduler::EveryJob.new(@scheduler, '1m', {}, lambda {})
57
+ t1 = ltz('America/Los_Angeles', 2015, 3, 8, 1, 55)
58
+ t2 = ltz('America/Los_Angeles', 2015, 3, 8, 3, 05)
59
+ job.next_time = t1
60
+ occurrences = job.occurrences(t1, t2)
61
+
62
+ expect(occurrences.length).to eq(11)
63
+ end
64
+ end
65
+
66
+ context 'first_at/in' do
67
+
68
+ it 'triggers for the first time at first_at' do
69
+
70
+ t = Time.now
71
+
72
+ job = @scheduler.schedule_every '3s', :first_in => '1s' do; end
73
+
74
+ sleep 2
75
+
76
+ #p [ t, t.to_f ]
77
+ #p [ job.last_time, job.last_time.to_f ]
78
+ #p [ job.first_at, job.first_at.to_f ]
79
+
80
+ expect(job.first_at).to be_within_1s_of(t + 2)
81
+ expect(job.last_time).to be_within_1s_of(job.first_at)
82
+ end
83
+
84
+ describe '#first_at=' do
85
+
86
+ it 'alters @next_time' do
87
+
88
+ job = @scheduler.schedule_every '3s', :first_in => '10s' do; end
89
+
90
+ fa0 = job.first_at
91
+ nt0 = job.next_time
92
+
93
+ job.first_at = Time.now + 3
94
+
95
+ fa1 = job.first_at
96
+ nt1 = job.next_time
97
+
98
+ expect(nt0).to eq(fa0)
99
+ expect(nt1).to eq(fa1)
100
+ end
101
+ end
102
+ end
103
+ end
104
+
@@ -0,0 +1,20 @@
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::InJob do
12
+
13
+ before :each do
14
+ @scheduler = Rufus::Scheduler.new
15
+ end
16
+ after :each do
17
+ @scheduler.shutdown
18
+ end
19
+ end
20
+
@@ -0,0 +1,68 @@
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::IntervalJob do
12
+
13
+ before :each do
14
+ @scheduler = Rufus::Scheduler.new
15
+ end
16
+ after :each do
17
+ @scheduler.shutdown
18
+ end
19
+
20
+ describe '#interval' do
21
+
22
+ it 'returns the scheduled interval' do
23
+
24
+ job = @scheduler.schedule_interval('1h') do; end
25
+
26
+ expect(job.interval).to eq(3600)
27
+ end
28
+ end
29
+
30
+ context 'first_at/in' do
31
+
32
+ it 'triggers for the first time at first_at' do
33
+
34
+ t = Time.now
35
+
36
+ job = @scheduler.schedule_interval '3s', :first_in => '1s' do; end
37
+
38
+ sleep 2
39
+
40
+ #p [ t, t.to_f ]
41
+ #p [ job.last_time, job.last_time.to_f ]
42
+ #p [ job.first_at, job.first_at.to_f ]
43
+
44
+ expect(job.first_at).to be_within_1s_of(t + 2)
45
+ expect(job.last_time).to be_within_1s_of(job.first_at)
46
+ end
47
+
48
+ describe '#first_at=' do
49
+
50
+ it 'alters @next_time' do
51
+
52
+ job = @scheduler.schedule_interval '3s', :first_in => '10s' do; end
53
+
54
+ fa0 = job.first_at
55
+ nt0 = job.next_time
56
+
57
+ job.first_at = Time.now + 3
58
+
59
+ fa1 = job.first_at
60
+ nt1 = job.next_time
61
+
62
+ expect(nt0).to eq(fa0)
63
+ expect(nt1).to eq(fa1)
64
+ end
65
+ end
66
+ end
67
+ end
68
+