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
@@ -1,159 +0,0 @@
1
-
2
- #
3
- # a spec by Klaas Jan Wierenga
4
- #
5
-
6
- require 'spec_base'
7
-
8
-
9
-
10
- JOB_COUNT = 500 # 1000
11
- JOB_IDS = (1..JOB_COUNT).to_a
12
- NUM_RESCHEDULES = 5 # 10
13
- TRIGGER_DELAY = 4 # 15
14
-
15
-
16
- describe SCHEDULER_CLASS do
17
-
18
- # helper methods
19
-
20
- # Wait for a variable to become a certain value.
21
- # This method returns a block which loops waiting for the passed in
22
- # block paramter to have value 'target'.
23
- #
24
- def eventually(timeout = TRIGGER_DELAY * 2, precision = 1)
25
- lambda { |target|
26
- value = nil
27
- (timeout/precision).to_i.times do
28
- value = yield # read variable once
29
- # puts "got #{value}, expected #{target}"
30
- break if target == value
31
- sleep precision
32
- end
33
- target == value
34
- }
35
- end
36
-
37
- def benchmark
38
- now = Time.now
39
- yield
40
- benchmark = Time.now - now
41
- print " (scheduling took #{benchmark}s)"
42
- if benchmark > TRIGGER_DELAY
43
- puts "\nTEST RESULT INVALID/UNRELIABLE"
44
- puts "Scheduling took longer than TRIGGER_DELAY (#{TRIGGER_DELAY}s)."
45
- puts "Increase TRIGGER_DELAY to a value larger than largest scheduling time."
46
- end
47
- end
48
-
49
- def schedule_unschedule_same_ids_spec(mode)
50
- scheduler = SCHEDULER_CLASS.start_new
51
- benchmark { schedule_unschedule(scheduler, mode, NUM_RESCHEDULES) }
52
- JOB_COUNT.should satisfy &eventually { scheduler.all_jobs.size }
53
- JOB_IDS.sort.should == scheduler.find_jobs.map{ |job| job.job_id }.sort
54
- JOB_COUNT.should satisfy &eventually { @trigger_queue.size }
55
- @trigger_queue.size.should == JOB_COUNT
56
- scheduler.stop
57
- end
58
-
59
- def schedule_unschedule_unique_ids_spec(mode)
60
- scheduler = SCHEDULER_CLASS.start_new
61
- job_ids = []
62
- benchmark { job_ids = schedule_unschedule(scheduler, mode, NUM_RESCHEDULES, true) }
63
- JOB_COUNT.should satisfy &eventually { scheduler.all_jobs.size }
64
- job_ids.sort.should == scheduler.find_jobs.map{ |job| job.job_id }.sort
65
- JOB_COUNT.should satisfy &eventually { @trigger_queue.size }
66
- @trigger_queue.size.should == JOB_COUNT
67
- scheduler.stop
68
- end
69
-
70
- def scheduler_counts(scheduler)
71
- "all:%d at:%d cron:%d every:%d pending:%d" % [
72
- scheduler.all_jobs.size,
73
- scheduler.at_job_count,
74
- scheduler.cron_job_count,
75
- scheduler.every_job_count,
76
- scheduler.pending_job_count ]
77
- end
78
-
79
- def schedule_unschedule(scheduler, mode, num_reschedules, generate_ids=false)
80
- job_ids = schedule_jobs(scheduler, mode, generate_ids)
81
- 1.upto(num_reschedules) do
82
- unschedule_jobs(scheduler, job_ids)
83
- job_ids = schedule_jobs(scheduler, mode, generate_ids)
84
- end
85
- job_ids
86
- end
87
-
88
- def schedule_jobs(scheduler, mode, generate_ids=false)
89
- job_ids = []
90
- JOB_IDS.each do |job_id|
91
- case mode
92
- when :cron
93
- job_ids << scheduler.cron(
94
- "%d * * * * *" % @cron_trigger,
95
- { :job_id => (generate_ids ? nil : job_id) },
96
- &@trigger_proc
97
- ).job_id
98
- when :at
99
- job_ids << scheduler.at(
100
- @at_trigger,
101
- { :job_id => (generate_ids ? nil : job_id) },
102
- &@trigger_proc
103
- ).job_id
104
- when :every
105
- job_ids << scheduler.every(
106
- @every_trigger,
107
- { :job_id => (generate_ids ? nil : job_id) },
108
- &@trigger_proc
109
- ).job_id
110
- else
111
- raise ArgumentError
112
- end
113
- end
114
- job_ids
115
- end
116
-
117
- def unschedule_jobs(scheduler, job_ids)
118
- job_ids.each { |job_id| scheduler.unschedule(job_id) }
119
- end
120
-
121
- # the actual tests
122
-
123
- before(:each) do
124
- @trigger_queue = Queue.new
125
- @cron_trigger = ((Time.now.to_i%60) + TRIGGER_DELAY) % 60 # 30 seconds from now
126
- @at_trigger = Time.now + TRIGGER_DELAY
127
- @every_trigger = "#{TRIGGER_DELAY}s"
128
- @trigger_proc = lambda { |job| @trigger_queue << job.job_id }
129
- end
130
-
131
- after(:each) do
132
- @trigger_queue = nil
133
- end
134
-
135
- it "sustains frequent schedule/unschedule 'cron' jobs with same ids" do
136
- schedule_unschedule_same_ids_spec(:cron)
137
- end
138
-
139
- it "sustains frequent schedule/unschedule 'at' jobs with same ids" do
140
- schedule_unschedule_same_ids_spec(:at)
141
- end
142
-
143
- it "sustains frequent schedule/unschedule 'every' jobs same ids" do
144
- schedule_unschedule_same_ids_spec(:every)
145
- end
146
-
147
- it "sustains frequent schedule/unschedule 'cron' jobs with unique ids" do
148
- schedule_unschedule_unique_ids_spec(:cron)
149
- end
150
-
151
- it "sustains frequent schedule/unschedule 'at' jobs with unique ids" do
152
- schedule_unschedule_unique_ids_spec(:at)
153
- end
154
-
155
- it "sustains frequent schedule/unschedule 'every' jobs unique ids" do
156
- schedule_unschedule_unique_ids_spec(:every)
157
- end
158
- end
159
-
data/spec/timeout_spec.rb DELETED
@@ -1,148 +0,0 @@
1
-
2
- #
3
- # Specifying rufus-scheduler
4
- #
5
- # Sun May 3 15:44:28 JST 2009
6
- #
7
-
8
- require 'spec_base'
9
-
10
-
11
- describe "#{SCHEDULER_CLASS} timeouts" do
12
-
13
- before(:each) do
14
- @s = start_scheduler
15
- end
16
- after(:each) do
17
- stop_scheduler(@s)
18
- end
19
-
20
- it 'refuses to schedule a job with :timeout and :blocking' do
21
-
22
- lambda {
23
- @s.in '1s', :timeout => '3s', :blocking => true do
24
- end
25
- }.should raise_error(ArgumentError)
26
- end
27
-
28
- it 'schedules a dedicated job for the timeout' do
29
-
30
- @s.in '1s', :timeout => '3s' do
31
- sleep 5
32
- end
33
-
34
- @s.jobs.size.should == 1
35
-
36
- # the timeout job is left
37
-
38
- sleep 2
39
- @s.jobs.size.should == 1
40
- @s.find_by_tag('timeout').size.should == 1
41
- end
42
-
43
- it 'times out' do
44
-
45
- var = nil
46
- timedout = false
47
-
48
- @s.in '1s', :timeout => '1s' do
49
- begin
50
- sleep 2
51
- var = true
52
- rescue Rufus::Scheduler::TimeOutError => e
53
- timedout = true
54
- end
55
- end
56
-
57
- sleep 4
58
-
59
- var.should == nil
60
- @s.jobs.size.should == 0
61
- timedout.should == true
62
- end
63
-
64
- it 'dies silently if job finished before timeout' do
65
-
66
- var = nil
67
- timedout = false
68
-
69
- @s.in '1s', :timeout => '1s' do
70
- begin
71
- var = true
72
- rescue Rufus::Scheduler::TimeOutError => e
73
- timedout = true
74
- end
75
- end
76
-
77
- sleep 3
78
-
79
- var.should == true
80
- @s.jobs.size.should == 0
81
- timedout.should == false
82
- end
83
-
84
- it 'does not timeout other jobs (in case of every)' do
85
-
86
- timeouts = []
87
-
88
- @s.every '1s', :timeout => '1s500' do
89
- start = Time.now
90
- begin
91
- sleep 2.0
92
- rescue Rufus::Scheduler::TimeOutError => e
93
- timeouts << (Time.now - start)
94
- end
95
- end
96
-
97
- sleep 5.5
98
-
99
- timeouts.size.should == 3
100
- timeouts.each { |to| to.should be_within(0.5).of(1.5) }
101
- end
102
-
103
- it 'points to their "parent" job' do
104
-
105
- @s.in '1s', :timeout => '3s', :job_id => 'nada' do
106
- sleep 4
107
- end
108
-
109
- sleep 2
110
-
111
- @s.jobs.values.first.parent.job_id.should == 'nada'
112
- end
113
-
114
- it 'does not survive their job' do
115
-
116
- @s.in '1s', :timeout => '3s' do
117
- sleep 0.100
118
- end
119
-
120
- sleep 2
121
-
122
- @s.jobs.size.should == 0
123
- end
124
-
125
- it 'times out properly after waiting for a mutex' do
126
-
127
- mutex = Mutex.new
128
- timedout = false
129
-
130
- @s.in '0s', :mutex => mutex do
131
- sleep 1
132
- end
133
-
134
- @s.in '0s', :mutex => mutex, :timeout => 0.1 do
135
- begin
136
- sleep 2
137
- rescue Rufus::Scheduler::TimeOutError => e
138
- timedout = true
139
- end
140
- end
141
-
142
- sleep 2
143
-
144
- @s.jobs.size.should == 0
145
- timedout.should be_true
146
- end
147
- end
148
-
data/test/kjw.rb DELETED
@@ -1,113 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- #
4
- # A test by http://twitter.com/kjw
5
- #
6
-
7
- require 'test/unit'
8
- $LOAD_PATH << 'lib'
9
- require 'rufus/sc/scheduler'
10
-
11
- require 'rubygems'
12
- require 'eventmachine'
13
-
14
- class CronTest < Test::Unit::TestCase
15
-
16
- #
17
- # Stress test program for rufus-scheduler
18
- #
19
-
20
- SECONDS_FROM_NOW = 30
21
- MODE = :cron
22
- JOB_COUNT = 1000
23
- JOB_IDS = (1..JOB_COUNT).to_a
24
- NUM_RESCHEDULES = 20
25
-
26
- def setup
27
- @trigger_queue = Queue.new
28
- end
29
-
30
- def test_stress_schedule_unschedule_plain_cron
31
- stress_schedule_unschedule(:cron, Rufus::Scheduler::PlainScheduler.start_new)
32
- end
33
-
34
- def test_stress_schedule_unschedule_plain_at
35
- stress_schedule_unschedule(:at, Rufus::Scheduler::PlainScheduler.start_new)
36
- end
37
-
38
- def test_stress_schedule_unschedule_plain_every
39
- stress_schedule_unschedule(:every, Rufus::Scheduler::PlainScheduler.start_new)
40
- end
41
-
42
- def test_stress_schedule_unschedule_em_cron
43
- stress_schedule_unschedule(:cron, Rufus::Scheduler::EmScheduler.start_new)
44
- end
45
-
46
- def test_stress_schedule_unschedule_em_at
47
- stress_schedule_unschedule(:at, Rufus::Scheduler::EmScheduler.start_new)
48
- end
49
-
50
- def test_stress_schedule_unschedule_em_every
51
- stress_schedule_unschedule(:every, Rufus::Scheduler::EmScheduler.start_new)
52
- end
53
-
54
- protected
55
-
56
- def stress_schedule_unschedule(mode, scheduler)
57
-
58
- # Schedule all jobs, then unschedule and (re)schedule a number of times
59
- schedule_unschedule(scheduler, mode, NUM_RESCHEDULES)
60
-
61
- # give scheduler thread 10 seconds to process the schedule and unschedule requests
62
- # but don't wait for the jobs to trigger (which is in less than 30 seconds)
63
- sleep 10
64
- # print_scheduler_counts(scheduler, 10)
65
-
66
- # by now the scheduler should have processed everything, check
67
- assert(JOB_IDS.sort == scheduler.find_jobs.map{ |job| job.job_id }.sort)
68
- sleep SECONDS_FROM_NOW # wait for jobs to trigger
69
- assert(JOB_COUNT == @trigger_queue.size)
70
- end
71
-
72
- def schedule_unschedule(scheduler, mode, num_reschedules)
73
- schedule_jobs(scheduler, mode)
74
- 1.upto(num_reschedules) do
75
- sleep 0.01 # cause schedule's to happen before unscheduling
76
- unschedule_jobs(scheduler)
77
- schedule_jobs(scheduler, mode)
78
- end
79
- end
80
-
81
- def print_scheduler_counts(scheduler, seconds)
82
- 1.upto(seconds) do
83
- puts "all:%d at:%d cron:%d every:%d pending:%d" % [
84
- scheduler.all_jobs.size,
85
- scheduler.at_job_count,
86
- scheduler.cron_job_count,
87
- scheduler.every_job_count,
88
- scheduler.pending_job_count]
89
- sleep 1
90
- end
91
- end
92
-
93
- def schedule_jobs(scheduler, mode)
94
- trigger_proc = lambda { |params| @trigger_queue << params[:job_id] }
95
- JOB_IDS.each do |job_id|
96
- case mode
97
- when :at
98
- scheduler.at(Time.now + SECONDS_FROM_NOW, {:job_id => job_id}, &trigger_proc)
99
- when :every
100
- scheduler.every("#{SECONDS_FROM_NOW}s", {:job_id => job_id}, &trigger_proc)
101
- when :cron
102
- scheduler.cron("%d * * * * *" % ((Time.now.to_i%60) + SECONDS_FROM_NOW) % 60,
103
- {:job_id => job_id}, &trigger_proc)
104
- end
105
- end
106
- end
107
-
108
- def unschedule_jobs(scheduler)
109
- JOB_IDS.each { |job_id| scheduler.unschedule(job_id) }
110
- end
111
-
112
- end
113
-
data/test/t.rb DELETED
@@ -1,20 +0,0 @@
1
-
2
- $:.unshift('lib')
3
-
4
- require 'rubygems'
5
- require 'rufus/scheduler/em'
6
-
7
- # scheduler
8
-
9
-
10
- s = Rufus::Scheduler.start_new
11
-
12
- puts Time.now.to_s
13
-
14
- s.in('1s') do
15
- p [ :in, Time.now.to_s ]
16
- exit 0
17
- end
18
-
19
- s.join
20
-