tanzeeb-rufus-scheduler 2.0.7.2
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +2 -0
- data/CHANGELOG.txt +43 -0
- data/CREDITS.txt +36 -0
- data/LICENSE.txt +21 -0
- data/README.rdoc +388 -0
- data/Rakefile +86 -0
- data/TODO.txt +57 -0
- data/lib/rufus-scheduler.rb +3 -0
- data/lib/rufus/otime.rb +3 -0
- data/lib/rufus/sc/cronline.rb +281 -0
- data/lib/rufus/sc/jobqueues.rb +160 -0
- data/lib/rufus/sc/jobs.rb +363 -0
- data/lib/rufus/sc/rtime.rb +365 -0
- data/lib/rufus/sc/scheduler.rb +481 -0
- data/lib/rufus/sc/version.rb +32 -0
- data/lib/rufus/scheduler.rb +55 -0
- data/misc/cronline_next_time_cost.rb +14 -0
- data/spec/at_in_spec.rb +48 -0
- data/spec/at_spec.rb +121 -0
- data/spec/blocking_spec.rb +54 -0
- data/spec/cron_spec.rb +122 -0
- data/spec/cronline_spec.rb +163 -0
- data/spec/every_spec.rb +229 -0
- data/spec/exception_spec.rb +77 -0
- data/spec/in_spec.rb +165 -0
- data/spec/rtime_spec.rb +93 -0
- data/spec/schedulable_spec.rb +79 -0
- data/spec/scheduler_spec.rb +81 -0
- data/spec/spec.rb +14 -0
- data/spec/spec_base.rb +82 -0
- data/spec/stress_schedule_unschedule_spec.rb +155 -0
- data/spec/timeout_spec.rb +125 -0
- data/tanzeeb-rufus-scheduler.gemspec +97 -0
- data/test/kjw.rb +113 -0
- data/test/t.rb +20 -0
- metadata +160 -0
data/spec/in_spec.rb
ADDED
@@ -0,0 +1,165 @@
|
|
1
|
+
|
2
|
+
#
|
3
|
+
# Specifying rufus-scheduler
|
4
|
+
#
|
5
|
+
# Sat Mar 21 17:36:36 JST 2009
|
6
|
+
#
|
7
|
+
|
8
|
+
require File.dirname(__FILE__) + '/spec_base'
|
9
|
+
|
10
|
+
|
11
|
+
describe "#{SCHEDULER_CLASS}#in" do
|
12
|
+
|
13
|
+
before do
|
14
|
+
@s = start_scheduler
|
15
|
+
end
|
16
|
+
after do
|
17
|
+
stop_scheduler(@s)
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'should have job ids with the class name in it' do
|
21
|
+
|
22
|
+
j0 = @s.in(1) {}
|
23
|
+
j0.job_id.should.match(/Rufus::Scheduler::InJob/)
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'should track scheduled in jobs' do
|
27
|
+
|
28
|
+
@s.in(1) {}
|
29
|
+
|
30
|
+
wait_next_tick
|
31
|
+
@s.jobs.size.should.equal(1)
|
32
|
+
|
33
|
+
sleep 1.5
|
34
|
+
|
35
|
+
@s.jobs.size.should.equal(0)
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'should schedule in 1' do
|
39
|
+
|
40
|
+
var = nil
|
41
|
+
|
42
|
+
@s.in 1 do
|
43
|
+
var = true
|
44
|
+
end
|
45
|
+
|
46
|
+
var.should.be.nil
|
47
|
+
sleep 1.5
|
48
|
+
|
49
|
+
var.should.be.true
|
50
|
+
end
|
51
|
+
|
52
|
+
it 'should schedule in 1.0' do
|
53
|
+
|
54
|
+
var = nil
|
55
|
+
|
56
|
+
@s.in 1.0 do
|
57
|
+
var = true
|
58
|
+
end
|
59
|
+
|
60
|
+
var.should.be.nil
|
61
|
+
sleep 1.5
|
62
|
+
|
63
|
+
var.should.be.true
|
64
|
+
end
|
65
|
+
|
66
|
+
it 'should schedule in 1s' do
|
67
|
+
|
68
|
+
var = nil
|
69
|
+
|
70
|
+
@s.in '1s' do
|
71
|
+
var = true
|
72
|
+
end
|
73
|
+
|
74
|
+
var.should.be.nil
|
75
|
+
sleep 1.5
|
76
|
+
|
77
|
+
var.should.be.true
|
78
|
+
end
|
79
|
+
|
80
|
+
it 'should trigger [almost] immediately jobs in the past' do
|
81
|
+
|
82
|
+
var = nil
|
83
|
+
|
84
|
+
@s.in -2 do
|
85
|
+
var = true
|
86
|
+
end
|
87
|
+
|
88
|
+
#wait_next_tick
|
89
|
+
sleep 0.550
|
90
|
+
|
91
|
+
var.should.be.true
|
92
|
+
@s.jobs.should.be.empty
|
93
|
+
end
|
94
|
+
|
95
|
+
it 'should not trigger jobs in the past when :discard_past => true' do
|
96
|
+
|
97
|
+
var = nil
|
98
|
+
|
99
|
+
@s.in -2, :discard_past => true do
|
100
|
+
var = true
|
101
|
+
end
|
102
|
+
|
103
|
+
var.should.be.nil
|
104
|
+
@s.jobs.should.be.empty
|
105
|
+
end
|
106
|
+
|
107
|
+
it 'should unschedule job' do
|
108
|
+
|
109
|
+
job = @s.in '2d' do
|
110
|
+
end
|
111
|
+
|
112
|
+
wait_next_tick
|
113
|
+
|
114
|
+
@s.jobs.size.should.equal(1)
|
115
|
+
|
116
|
+
@s.unschedule(job.job_id)
|
117
|
+
|
118
|
+
@s.jobs.size.should.equal(0)
|
119
|
+
end
|
120
|
+
|
121
|
+
it 'should accept tags for jobs' do
|
122
|
+
|
123
|
+
job = @s.in '2d', :tags => 'spec' do
|
124
|
+
end
|
125
|
+
|
126
|
+
wait_next_tick
|
127
|
+
|
128
|
+
@s.find_by_tag('spec').size.should.equal(1)
|
129
|
+
@s.find_by_tag('spec').first.job_id.should.equal(job.job_id)
|
130
|
+
end
|
131
|
+
|
132
|
+
end
|
133
|
+
|
134
|
+
describe Rufus::Scheduler::InJob do
|
135
|
+
|
136
|
+
before do
|
137
|
+
@s = start_scheduler
|
138
|
+
end
|
139
|
+
after do
|
140
|
+
stop_scheduler(@s)
|
141
|
+
end
|
142
|
+
|
143
|
+
it 'should unschedule itself' do
|
144
|
+
|
145
|
+
job = @s.in '2d' do
|
146
|
+
end
|
147
|
+
|
148
|
+
wait_next_tick
|
149
|
+
|
150
|
+
job.unschedule
|
151
|
+
|
152
|
+
@s.jobs.size.should.equal(0)
|
153
|
+
end
|
154
|
+
|
155
|
+
it 'should respond to #next_time' do
|
156
|
+
|
157
|
+
t = Time.now + 3 * 3600
|
158
|
+
|
159
|
+
job = @s.in '3h' do
|
160
|
+
end
|
161
|
+
|
162
|
+
job.next_time.to_i.should.equal(t.to_i)
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
data/spec/rtime_spec.rb
ADDED
@@ -0,0 +1,93 @@
|
|
1
|
+
|
2
|
+
#
|
3
|
+
# Specifying rufus-scheduler
|
4
|
+
#
|
5
|
+
# Fri Mar 20 23:46:32 JST 2009
|
6
|
+
#
|
7
|
+
|
8
|
+
require File.dirname(__FILE__) + '/spec_base'
|
9
|
+
|
10
|
+
|
11
|
+
describe 'rufus/otime' do
|
12
|
+
|
13
|
+
def pts (s)
|
14
|
+
Rufus.parse_time_string(s)
|
15
|
+
end
|
16
|
+
|
17
|
+
def tts (f, opts={})
|
18
|
+
Rufus.to_time_string(f, opts)
|
19
|
+
end
|
20
|
+
|
21
|
+
def tdh (f, opts={})
|
22
|
+
Rufus.to_duration_hash(f, opts)
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'should parse duration strings' do
|
26
|
+
|
27
|
+
pts('5.0').should.equal(5.0)
|
28
|
+
pts('0.5').should.equal(0.5)
|
29
|
+
pts('.5').should.equal(0.5)
|
30
|
+
pts('5.').should.equal(5.0)
|
31
|
+
pts('500').should.equal(0.5)
|
32
|
+
pts('1000').should.equal(1.0)
|
33
|
+
pts('1').should.equal(0.001)
|
34
|
+
pts('1s').should.equal(1.0)
|
35
|
+
pts('1h').should.equal(3600.0)
|
36
|
+
pts('1h10s').should.equal(3610.0)
|
37
|
+
pts('1w2d').should.equal(777600.0)
|
38
|
+
pts('1d1w1d').should.equal(777600.0)
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'should generate duration strings' do
|
42
|
+
|
43
|
+
tts(0).should.equal('0s')
|
44
|
+
tts(0, :drop_seconds => true).should.equal('0m')
|
45
|
+
tts(60).should.equal('1m')
|
46
|
+
tts(61).should.equal('1m1s')
|
47
|
+
tts(3661).should.equal('1h1m1s')
|
48
|
+
tts(24 * 3600).should.equal('1d')
|
49
|
+
tts(7 * 24 * 3600 + 1).should.equal('1w1s')
|
50
|
+
tts(30 * 24 * 3600 + 1).should.equal('4w2d1s')
|
51
|
+
tts(30 * 24 * 3600 + 1, :months => true).should.equal('1M1s')
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'should compute duration hashes' do
|
55
|
+
|
56
|
+
tdh(0).should.equal({})
|
57
|
+
tdh(0.128).should.equal({ :ms => 128 })
|
58
|
+
tdh(60.127).should.equal({ :m => 1, :ms => 127 })
|
59
|
+
tdh(61.127).should.equal({ :m => 1, :s => 1, :ms => 127 })
|
60
|
+
tdh(61.127, :drop_seconds => true).should.equal({ :m => 1 })
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
describe 'rufus/otime#at_to_f' do
|
65
|
+
|
66
|
+
def atf (o)
|
67
|
+
Rufus.at_to_f(o)
|
68
|
+
end
|
69
|
+
|
70
|
+
it 'should turn Time at values to float' do
|
71
|
+
|
72
|
+
t = Time.now
|
73
|
+
tf = t.to_f.to_i.to_f
|
74
|
+
|
75
|
+
atf(t + 2).to_i.to_f.should.equal(tf + 2)
|
76
|
+
end
|
77
|
+
|
78
|
+
it 'should turn String at values to float' do
|
79
|
+
|
80
|
+
atf('Sat Mar 21 20:08:01 +0900 2009').should.equal(1237633681.0)
|
81
|
+
atf('Sat Mar 21 20:08:01 -0900 2009').should.equal(1237698481.0)
|
82
|
+
atf('Sat Mar 21 20:08:01 +0000 2009').should.equal(1237666081.0)
|
83
|
+
atf('Sat Mar 21 20:08:01 2009').should.equal(1237666081.0)
|
84
|
+
atf('Mar 21 20:08:01 2009').should.equal(1237666081.0)
|
85
|
+
atf('2009/03/21 20:08').should.equal(1237666080.0)
|
86
|
+
end
|
87
|
+
|
88
|
+
it 'should accept integers' do
|
89
|
+
|
90
|
+
atf(1).should.equal(1.0)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
@@ -0,0 +1,79 @@
|
|
1
|
+
|
2
|
+
#
|
3
|
+
# Specifying rufus-scheduler
|
4
|
+
#
|
5
|
+
# Tue May 5 14:47:16 JST 2009
|
6
|
+
#
|
7
|
+
|
8
|
+
require File.dirname(__FILE__) + '/spec_base'
|
9
|
+
|
10
|
+
|
11
|
+
describe Rufus::Scheduler::Schedulable do
|
12
|
+
|
13
|
+
before do
|
14
|
+
@s = start_scheduler
|
15
|
+
end
|
16
|
+
after do
|
17
|
+
stop_scheduler(@s)
|
18
|
+
end
|
19
|
+
|
20
|
+
class JobAlpha
|
21
|
+
attr_reader :value
|
22
|
+
def trigger (params)
|
23
|
+
@value = params
|
24
|
+
end
|
25
|
+
end
|
26
|
+
class JobBravo
|
27
|
+
attr_reader :value
|
28
|
+
def call (job)
|
29
|
+
@value = job
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'should schedule via :schedulable' do
|
34
|
+
|
35
|
+
j = JobAlpha.new
|
36
|
+
|
37
|
+
@s.in '1s', :schedulable => j
|
38
|
+
|
39
|
+
sleep 1.4
|
40
|
+
|
41
|
+
j.value.class.should.equal(Hash)
|
42
|
+
j.value[:job].class.should.equal(Rufus::Scheduler::InJob)
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'should honour schedulables that reply to :call' do
|
46
|
+
|
47
|
+
j = JobBravo.new
|
48
|
+
|
49
|
+
@s.in '1s', :schedulable => j
|
50
|
+
|
51
|
+
sleep 1.4
|
52
|
+
|
53
|
+
j.value.class.should.equal(Rufus::Scheduler::InJob)
|
54
|
+
end
|
55
|
+
|
56
|
+
it 'should accept trigger schedulables as second param' do
|
57
|
+
|
58
|
+
j = JobAlpha.new
|
59
|
+
|
60
|
+
@s.in '1s', j
|
61
|
+
|
62
|
+
sleep 1.4
|
63
|
+
|
64
|
+
j.value.class.should.equal(Hash)
|
65
|
+
j.value[:job].class.should.equal(Rufus::Scheduler::InJob)
|
66
|
+
end
|
67
|
+
|
68
|
+
it 'should accept call schedulables as second param' do
|
69
|
+
|
70
|
+
j = JobBravo.new
|
71
|
+
|
72
|
+
@s.in '1s', j
|
73
|
+
|
74
|
+
sleep 1.4
|
75
|
+
|
76
|
+
j.value.class.should.equal(Rufus::Scheduler::InJob)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
@@ -0,0 +1,81 @@
|
|
1
|
+
|
2
|
+
#
|
3
|
+
# Specifying rufus-scheduler
|
4
|
+
#
|
5
|
+
# Sat Mar 21 17:43:23 JST 2009
|
6
|
+
#
|
7
|
+
|
8
|
+
require File.dirname(__FILE__) + '/spec_base'
|
9
|
+
|
10
|
+
|
11
|
+
describe SCHEDULER_CLASS do
|
12
|
+
|
13
|
+
it 'should stop' do
|
14
|
+
|
15
|
+
var = nil
|
16
|
+
|
17
|
+
s = start_scheduler
|
18
|
+
s.in('3s') { var = true }
|
19
|
+
|
20
|
+
stop_scheduler(s)
|
21
|
+
|
22
|
+
var.should.be.nil
|
23
|
+
sleep 4
|
24
|
+
var.should.be.nil
|
25
|
+
end
|
26
|
+
|
27
|
+
unless SCHEDULER_CLASS == Rufus::Scheduler::EmScheduler
|
28
|
+
|
29
|
+
it 'should set a default scheduler thread name' do
|
30
|
+
|
31
|
+
s = start_scheduler
|
32
|
+
|
33
|
+
s.instance_variable_get(:@thread)['name'].should.match(
|
34
|
+
/Rufus::Scheduler::.*Scheduler - \d+\.\d+\.\d+/)
|
35
|
+
|
36
|
+
stop_scheduler(s)
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'should set the scheduler thread name' do
|
40
|
+
|
41
|
+
s = start_scheduler(:thread_name => 'nada')
|
42
|
+
s.instance_variable_get(:@thread)['name'].should.equal('nada')
|
43
|
+
|
44
|
+
stop_scheduler(s)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'should accept a custom frequency' do
|
49
|
+
|
50
|
+
var = nil
|
51
|
+
|
52
|
+
s = start_scheduler(:frequency => 3.0)
|
53
|
+
|
54
|
+
s.in('1s') { var = true }
|
55
|
+
|
56
|
+
sleep 1
|
57
|
+
var.should.be.nil
|
58
|
+
|
59
|
+
sleep 1
|
60
|
+
var.should.be.nil
|
61
|
+
|
62
|
+
sleep 2
|
63
|
+
var.should.be.true
|
64
|
+
|
65
|
+
stop_scheduler(s)
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
69
|
+
|
70
|
+
describe 'Rufus::Scheduler#start_new' do
|
71
|
+
|
72
|
+
it 'should piggyback EM if present and running' do
|
73
|
+
|
74
|
+
s = Rufus::Scheduler.start_new
|
75
|
+
|
76
|
+
s.class.should.equal(SCHEDULER_CLASS)
|
77
|
+
|
78
|
+
stop_scheduler(s)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
data/spec/spec.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
|
2
|
+
#
|
3
|
+
# specifying rufus-scheduler
|
4
|
+
#
|
5
|
+
# Fri Mar 20 22:54:46 JST 2009
|
6
|
+
#
|
7
|
+
|
8
|
+
specs = Dir["#{File.dirname(__FILE__)}/*_spec.rb"]
|
9
|
+
|
10
|
+
#specs = specs - [ 'spec/stress_schedule_unschedule_spec.rb' ]
|
11
|
+
# this spec was a bit longish (11m) now it's OK (66.78s)
|
12
|
+
|
13
|
+
specs.each { |path| load(path) }
|
14
|
+
|
data/spec/spec_base.rb
ADDED
@@ -0,0 +1,82 @@
|
|
1
|
+
|
2
|
+
#
|
3
|
+
# Specifying rufus-scheduler
|
4
|
+
#
|
5
|
+
# Fri Mar 20 22:53:33 JST 2009
|
6
|
+
#
|
7
|
+
|
8
|
+
|
9
|
+
#
|
10
|
+
# bacon
|
11
|
+
|
12
|
+
$:.unshift(File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib')))
|
13
|
+
|
14
|
+
require 'rubygems'
|
15
|
+
require 'fileutils'
|
16
|
+
|
17
|
+
|
18
|
+
$:.unshift(File.expand_path('~/tmp/bacon/lib')) # my own bacon for a while
|
19
|
+
|
20
|
+
require 'bacon'
|
21
|
+
|
22
|
+
puts
|
23
|
+
|
24
|
+
Bacon.summary_on_exit
|
25
|
+
|
26
|
+
|
27
|
+
#
|
28
|
+
# rufus/scheduler/em
|
29
|
+
|
30
|
+
# EM or plain ?
|
31
|
+
|
32
|
+
$plain = ! ARGV.include?('--em')
|
33
|
+
|
34
|
+
require 'rufus/scheduler'
|
35
|
+
|
36
|
+
if ( ! $plain)
|
37
|
+
|
38
|
+
require 'eventmachine'
|
39
|
+
|
40
|
+
unless (EM.reactor_running?)
|
41
|
+
|
42
|
+
Thread.new { EM.run { } }
|
43
|
+
|
44
|
+
sleep 0.200
|
45
|
+
while (not EM.reactor_running?)
|
46
|
+
Thread.pass
|
47
|
+
end
|
48
|
+
#
|
49
|
+
# all this waiting, especially for the JRuby eventmachine, which seems
|
50
|
+
# rather 'diesel'
|
51
|
+
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
SCHEDULER_CLASS = $plain ?
|
56
|
+
Rufus::Scheduler::PlainScheduler :
|
57
|
+
Rufus::Scheduler::EmScheduler
|
58
|
+
|
59
|
+
#
|
60
|
+
# helper methods
|
61
|
+
|
62
|
+
def start_scheduler (opts={})
|
63
|
+
SCHEDULER_CLASS.start_new(opts)
|
64
|
+
end
|
65
|
+
|
66
|
+
def stop_scheduler (s)
|
67
|
+
#s.stop(:stop_em => true)
|
68
|
+
#sleep 0.200 # give time to the EM to stop
|
69
|
+
s.stop
|
70
|
+
sleep 0.200
|
71
|
+
end
|
72
|
+
|
73
|
+
def wait_next_tick
|
74
|
+
if defined?(EM)
|
75
|
+
t = Thread.current
|
76
|
+
EM.next_tick { t.wakeup }
|
77
|
+
Thread.stop
|
78
|
+
else
|
79
|
+
sleep 0.500
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|