rufus-scheduler 2.0.24 → 3.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.txt +6 -0
- data/CREDITS.txt +4 -0
- data/README.md +1064 -0
- data/Rakefile +1 -4
- data/TODO.txt +145 -55
- data/lib/rufus/scheduler.rb +502 -26
- data/lib/rufus/{sc → scheduler}/cronline.rb +46 -17
- data/lib/rufus/{sc/version.rb → scheduler/job_array.rb} +56 -4
- data/lib/rufus/scheduler/jobs.rb +548 -0
- data/lib/rufus/scheduler/util.rb +318 -0
- data/rufus-scheduler.gemspec +30 -4
- data/spec/cronline_spec.rb +29 -8
- data/spec/error_spec.rb +116 -0
- data/spec/job_array_spec.rb +39 -0
- data/spec/job_at_spec.rb +58 -0
- data/spec/job_cron_spec.rb +67 -0
- data/spec/job_every_spec.rb +71 -0
- data/spec/job_in_spec.rb +20 -0
- data/spec/job_interval_spec.rb +68 -0
- data/spec/job_repeat_spec.rb +308 -0
- data/spec/job_spec.rb +387 -115
- data/spec/lockfile_spec.rb +61 -0
- data/spec/parse_spec.rb +203 -0
- data/spec/schedule_at_spec.rb +129 -0
- data/spec/schedule_cron_spec.rb +66 -0
- data/spec/schedule_every_spec.rb +109 -0
- data/spec/schedule_in_spec.rb +80 -0
- data/spec/schedule_interval_spec.rb +128 -0
- data/spec/scheduler_spec.rb +831 -124
- data/spec/spec_helper.rb +65 -0
- data/spec/threads_spec.rb +75 -0
- metadata +64 -59
- data/README.rdoc +0 -661
- data/lib/rufus/otime.rb +0 -3
- data/lib/rufus/sc/jobqueues.rb +0 -160
- data/lib/rufus/sc/jobs.rb +0 -471
- data/lib/rufus/sc/rtime.rb +0 -363
- data/lib/rufus/sc/scheduler.rb +0 -636
- data/spec/at_in_spec.rb +0 -47
- data/spec/at_spec.rb +0 -125
- data/spec/blocking_spec.rb +0 -64
- data/spec/cron_spec.rb +0 -134
- data/spec/every_spec.rb +0 -304
- data/spec/exception_spec.rb +0 -113
- data/spec/in_spec.rb +0 -150
- data/spec/mutex_spec.rb +0 -159
- data/spec/rtime_spec.rb +0 -137
- data/spec/schedulable_spec.rb +0 -97
- data/spec/spec_base.rb +0 -87
- data/spec/stress_schedule_unschedule_spec.rb +0 -159
- data/spec/timeout_spec.rb +0 -148
- data/test/kjw.rb +0 -113
- data/test/t.rb +0 -20
@@ -0,0 +1,61 @@
|
|
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
|
+
line.should 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
|
+
f.flock(File::LOCK_NB | File::LOCK_EX).should == 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
|
+
s0.started_at.should_not == nil
|
46
|
+
s1.started_at.should == 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
|
+
f.flock(File::LOCK_NB | File::LOCK_EX).should == 0
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
data/spec/parse_spec.rb
ADDED
@@ -0,0 +1,203 @@
|
|
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 do
|
12
|
+
|
13
|
+
describe '.parse' do
|
14
|
+
|
15
|
+
def parse(s)
|
16
|
+
Rufus::Scheduler.parse(s)
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'parses duration strings' do
|
20
|
+
|
21
|
+
parse('1.0d1.0w1.0d').should == 777600.0
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'parses datetimes' do
|
25
|
+
|
26
|
+
# local
|
27
|
+
|
28
|
+
parse('Sun Nov 18 16:01:00 2012').strftime('%c').should ==
|
29
|
+
'Sun Nov 18 16:01:00 2012'
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'parses datetimes with timezones' do
|
33
|
+
|
34
|
+
parse('Sun Nov 18 16:01:00 2012 Japan').getutc.strftime('%c').should ==
|
35
|
+
'Sun Nov 18 07:01:00 2012'
|
36
|
+
|
37
|
+
parse('Sun Nov 18 16:01:00 2012 Zulu').getutc.strftime('%c').should ==
|
38
|
+
'Sun Nov 18 16:01:00 2012'
|
39
|
+
|
40
|
+
parse('Sun Nov 18 16:01:00 Japan 2012').getutc.strftime('%c').should ==
|
41
|
+
'Sun Nov 18 07:01:00 2012'
|
42
|
+
|
43
|
+
parse('Japan Sun Nov 18 16:01:00 2012').getutc.strftime('%c').should ==
|
44
|
+
'Sun Nov 18 07:01:00 2012'
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'parses datetimes with named timezones' do
|
48
|
+
|
49
|
+
parse(
|
50
|
+
'Sun Nov 18 16:01:00 2012 Europe/Berlin'
|
51
|
+
).strftime('%c %z').should ==
|
52
|
+
'Sun Nov 18 15:01:00 2012 +0000'
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'parses datetimes (with the local timezone implicitely)' do
|
56
|
+
|
57
|
+
localzone = Time.now.strftime('%z')
|
58
|
+
|
59
|
+
parse('Sun Nov 18 16:01:00 2012').strftime('%c %z').should ==
|
60
|
+
"Sun Nov 18 16:01:00 2012 #{localzone}"
|
61
|
+
end
|
62
|
+
|
63
|
+
it 'parses cronlines' do
|
64
|
+
|
65
|
+
out = parse('* * * * *')
|
66
|
+
|
67
|
+
out.class.should == Rufus::Scheduler::CronLine
|
68
|
+
out.original.should == '* * * * *'
|
69
|
+
|
70
|
+
parse('10 23 * * *').class.should == Rufus::Scheduler::CronLine
|
71
|
+
parse('* 23 * * *').class.should == Rufus::Scheduler::CronLine
|
72
|
+
end
|
73
|
+
|
74
|
+
it 'raises on unparseable input' do
|
75
|
+
|
76
|
+
lambda {
|
77
|
+
parse('nada')
|
78
|
+
}.should raise_error(ArgumentError, 'couldn\'t parse "nada"')
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
describe '.parse_duration' do
|
83
|
+
|
84
|
+
def pd(s)
|
85
|
+
Rufus::Scheduler.parse_duration(s)
|
86
|
+
end
|
87
|
+
|
88
|
+
it 'parses duration strings' do
|
89
|
+
|
90
|
+
pd('-1.0d1.0w1.0d').should == -777600.0
|
91
|
+
pd('-1d1w1d').should == -777600.0
|
92
|
+
pd('-1w2d').should == -777600.0
|
93
|
+
pd('-1h10s').should == -3610.0
|
94
|
+
pd('-1h').should == -3600.0
|
95
|
+
pd('-5.').should == -5.0
|
96
|
+
pd('-2.5s').should == -2.5
|
97
|
+
pd('-1s').should == -1.0
|
98
|
+
pd('-500').should == -500
|
99
|
+
pd('').should == 0.0
|
100
|
+
pd('5.0').should == 5.0
|
101
|
+
pd('0.5').should == 0.5
|
102
|
+
pd('.5').should == 0.5
|
103
|
+
pd('5.').should == 5.0
|
104
|
+
pd('500').should == 500
|
105
|
+
pd('1000').should == 1000
|
106
|
+
pd('1').should == 1.0
|
107
|
+
pd('1s').should == 1.0
|
108
|
+
pd('2.5s').should == 2.5
|
109
|
+
pd('1h').should == 3600.0
|
110
|
+
pd('1h10s').should == 3610.0
|
111
|
+
pd('1w2d').should == 777600.0
|
112
|
+
pd('1d1w1d').should == 777600.0
|
113
|
+
pd('1.0d1.0w1.0d').should == 777600.0
|
114
|
+
|
115
|
+
pd('.5m').should == 30.0
|
116
|
+
pd('5.m').should == 300.0
|
117
|
+
pd('1m.5s').should == 60.5
|
118
|
+
pd('-.5m').should == -30.0
|
119
|
+
|
120
|
+
pd('1').should == 1
|
121
|
+
pd('0.1').should == 0.1
|
122
|
+
pd('1s').should == 1
|
123
|
+
end
|
124
|
+
|
125
|
+
it 'calls #to_s on its input' do
|
126
|
+
|
127
|
+
pd(0.1).should == 0.1
|
128
|
+
end
|
129
|
+
|
130
|
+
it 'raises on wrong duration strings' do
|
131
|
+
|
132
|
+
lambda { pd('-') }.should raise_error(ArgumentError)
|
133
|
+
lambda { pd('h') }.should raise_error(ArgumentError)
|
134
|
+
lambda { pd('whatever') }.should raise_error(ArgumentError)
|
135
|
+
lambda { pd('hms') }.should raise_error(ArgumentError)
|
136
|
+
|
137
|
+
lambda { pd(' 1h ') }.should raise_error(ArgumentError)
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
describe '.to_duration' do
|
142
|
+
|
143
|
+
def td(o, opts={})
|
144
|
+
Rufus::Scheduler.to_duration(o, opts)
|
145
|
+
end
|
146
|
+
|
147
|
+
it 'turns integers into duration strings' do
|
148
|
+
|
149
|
+
td(0).should == '0s'
|
150
|
+
td(60).should == '1m'
|
151
|
+
td(61).should == '1m1s'
|
152
|
+
td(3661).should == '1h1m1s'
|
153
|
+
td(24 * 3600).should == '1d'
|
154
|
+
td(7 * 24 * 3600 + 1).should == '1w1s'
|
155
|
+
td(30 * 24 * 3600 + 1).should == '4w2d1s'
|
156
|
+
end
|
157
|
+
|
158
|
+
it 'ignores seconds and milliseconds if :drop_seconds => true' do
|
159
|
+
|
160
|
+
td(0, :drop_seconds => true).should == '0m'
|
161
|
+
td(5, :drop_seconds => true).should == '0m'
|
162
|
+
td(61, :drop_seconds => true).should == '1m'
|
163
|
+
end
|
164
|
+
|
165
|
+
it 'displays months if :months => true' do
|
166
|
+
|
167
|
+
td(1, :months => true).should == '1s'
|
168
|
+
td(30 * 24 * 3600 + 1, :months => true).should == '1M1s'
|
169
|
+
end
|
170
|
+
|
171
|
+
it 'turns floats into duration strings' do
|
172
|
+
|
173
|
+
td(0.1).should == '100'
|
174
|
+
td(1.1).should == '1s100'
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
describe '.to_duration_hash' do
|
179
|
+
|
180
|
+
def tdh(o, opts={})
|
181
|
+
Rufus::Scheduler.to_duration_hash(o, opts)
|
182
|
+
end
|
183
|
+
|
184
|
+
it 'turns integers duration hashes' do
|
185
|
+
|
186
|
+
tdh(0).should == {}
|
187
|
+
tdh(60).should == { :m => 1 }
|
188
|
+
end
|
189
|
+
|
190
|
+
it 'turns floats duration hashes' do
|
191
|
+
|
192
|
+
tdh(0.128).should == { :ms => 128 }
|
193
|
+
tdh(60.127).should == { :m => 1, :ms => 127 }
|
194
|
+
end
|
195
|
+
|
196
|
+
it 'drops seconds and milliseconds if :drop_seconds => true' do
|
197
|
+
|
198
|
+
tdh(61.127).should == { :m => 1, :s => 1, :ms => 127 }
|
199
|
+
tdh(61.127, :drop_seconds => true).should == { :m => 1 }
|
200
|
+
end
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
@@ -0,0 +1,129 @@
|
|
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 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 '#at' do
|
21
|
+
|
22
|
+
it 'raises if the block to schedule is missing' do
|
23
|
+
|
24
|
+
lambda {
|
25
|
+
@scheduler.at(Time.now + 3600)
|
26
|
+
}.should raise_error(ArgumentError)
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'returns a job id' do
|
30
|
+
|
31
|
+
job_id =
|
32
|
+
@scheduler.at(Time.now + 3600) do
|
33
|
+
end
|
34
|
+
|
35
|
+
job_id.class.should == String
|
36
|
+
job_id.should match(/^at_/)
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'returns a job if :job => true' do
|
40
|
+
|
41
|
+
job =
|
42
|
+
@scheduler.at(Time.now + 3600, :job => true) do
|
43
|
+
end
|
44
|
+
|
45
|
+
job.class.should == Rufus::Scheduler::AtJob
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'adds a job' do
|
49
|
+
|
50
|
+
t = Time.now + 3600
|
51
|
+
|
52
|
+
@scheduler.at(t) do
|
53
|
+
end
|
54
|
+
|
55
|
+
@scheduler.jobs.size.should == 1
|
56
|
+
@scheduler.jobs.first.class.should == Rufus::Scheduler::AtJob
|
57
|
+
@scheduler.jobs.first.time.should == t
|
58
|
+
end
|
59
|
+
|
60
|
+
it 'triggers a job' do
|
61
|
+
|
62
|
+
a = false
|
63
|
+
|
64
|
+
@scheduler.at(Time.now + 0.100) do
|
65
|
+
a = true
|
66
|
+
end
|
67
|
+
|
68
|
+
sleep 0.4
|
69
|
+
|
70
|
+
a.should == true
|
71
|
+
end
|
72
|
+
|
73
|
+
it 'removes the job after execution' do
|
74
|
+
|
75
|
+
@scheduler.at(Time.now + 0.100) do
|
76
|
+
end
|
77
|
+
|
78
|
+
sleep 0.4
|
79
|
+
|
80
|
+
@scheduler.jobs.size.should == 0
|
81
|
+
end
|
82
|
+
|
83
|
+
it 'accepts a Time instance' do
|
84
|
+
|
85
|
+
t = Time.now + 3600
|
86
|
+
|
87
|
+
job = @scheduler.at(t, :job => true) {}
|
88
|
+
|
89
|
+
job.time.should == t
|
90
|
+
end
|
91
|
+
|
92
|
+
it 'accepts a time string' do
|
93
|
+
|
94
|
+
job = @scheduler.at('2100-12-12 20:30', :job => true) {}
|
95
|
+
|
96
|
+
job.time.should == Time.parse('2100-12-12 20:30')
|
97
|
+
end
|
98
|
+
|
99
|
+
it 'accepts a time string with a delta timezone' do
|
100
|
+
|
101
|
+
job = @scheduler.at('2100-12-12 20:30 -0200', :job => true) {}
|
102
|
+
|
103
|
+
job.time.should == Time.parse('2100-12-12 20:30 -0200')
|
104
|
+
end
|
105
|
+
|
106
|
+
it 'accepts a time string with a named timezone' do
|
107
|
+
|
108
|
+
job = @scheduler.at('2050-12-12 20:30 Europe/Berlin', :job => true) {}
|
109
|
+
|
110
|
+
job.time.strftime('%c %z').should == 'Mon Dec 12 19:30:00 2050 +0000'
|
111
|
+
end
|
112
|
+
|
113
|
+
it 'accepts a Chronic time string (if Chronic is present)'
|
114
|
+
it 'accepts an ActiveSupport time thinggy'
|
115
|
+
end
|
116
|
+
|
117
|
+
describe '#schedule_at' do
|
118
|
+
|
119
|
+
it 'returns a job' do
|
120
|
+
|
121
|
+
job = @scheduler.schedule_at(Time.now + 3600) do
|
122
|
+
end
|
123
|
+
|
124
|
+
job.class.should == Rufus::Scheduler::AtJob
|
125
|
+
job.id.should match(/^at_/)
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
@@ -0,0 +1,66 @@
|
|
1
|
+
|
2
|
+
#
|
3
|
+
# Specifying rufus-scheduler
|
4
|
+
#
|
5
|
+
# Sat Jul 13 04:52:08 JST 2013
|
6
|
+
#
|
7
|
+
# In the train between Bern and Fribourg, riding back
|
8
|
+
# from the @ruvetia drinkup
|
9
|
+
#
|
10
|
+
|
11
|
+
require 'spec_helper'
|
12
|
+
|
13
|
+
|
14
|
+
describe Rufus::Scheduler do
|
15
|
+
|
16
|
+
before :each do
|
17
|
+
@scheduler = Rufus::Scheduler.new
|
18
|
+
end
|
19
|
+
after :each do
|
20
|
+
@scheduler.shutdown
|
21
|
+
end
|
22
|
+
|
23
|
+
describe '#cron' do
|
24
|
+
|
25
|
+
it 'schedules' do
|
26
|
+
|
27
|
+
counter = 0
|
28
|
+
|
29
|
+
sleep_until_next_second
|
30
|
+
sleep 0.3 # make sure to schedule right after a scheduler 'tick'
|
31
|
+
|
32
|
+
job =
|
33
|
+
@scheduler.cron '* * * * * *', :job => true do
|
34
|
+
counter = counter + 1
|
35
|
+
end
|
36
|
+
|
37
|
+
sleep_until_next_second
|
38
|
+
sleep_until_next_second
|
39
|
+
sleep 0.3 # be sure to be well into the second
|
40
|
+
|
41
|
+
counter.should == 2
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'raises if the job frequency is higher than the scheduler frequency' do
|
45
|
+
|
46
|
+
@scheduler.frequency = 10
|
47
|
+
|
48
|
+
lambda {
|
49
|
+
@scheduler.cron '* * * * * *' do; end
|
50
|
+
}.should raise_error(ArgumentError)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
describe '#schedule_cron' do
|
55
|
+
|
56
|
+
it 'returns a CronJob instance' do
|
57
|
+
|
58
|
+
job = @scheduler.schedule_cron '* * * * *' do; end
|
59
|
+
|
60
|
+
job.class.should == Rufus::Scheduler::CronJob
|
61
|
+
job.original.should == '* * * * *'
|
62
|
+
job.job_id.should match(/^cron_/)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|