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