rufus-scheduler 2.0.24 → 3.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.
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
+