tanzeeb-rufus-scheduler 2.0.7.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,155 @@
1
+
2
+ $LOAD_PATH << 'lib'
3
+ require 'rufus/sc/scheduler'
4
+
5
+ require 'rubygems'
6
+ require 'eventmachine'
7
+
8
+ #require 'spec/autorun'
9
+ require File.dirname(__FILE__) + '/spec_base'
10
+
11
+ JOB_COUNT = 500 # 1000
12
+ JOB_IDS = (1..JOB_COUNT).to_a
13
+ NUM_RESCHEDULES = 5 # 10
14
+ TRIGGER_DELAY = 4 # 15
15
+
16
+ describe SCHEDULER_CLASS do
17
+
18
+ # helper methods
19
+
20
+ #
21
+ # Wait for a variable to become a certain value.
22
+ # This method returns a block which loops waiting for the passed in
23
+ # block paramter to have value 'target'.
24
+ #
25
+ def eventually(timeout = TRIGGER_DELAY * 2, precision = 1)
26
+ lambda { |target|
27
+ value = nil
28
+ (timeout/precision).to_i.times do
29
+ value = yield # read variable once
30
+ # puts "got #{value}, expected #{target}"
31
+ break if target == value
32
+ sleep precision
33
+ end
34
+ target == value
35
+ }
36
+ end
37
+
38
+ def benchmark
39
+ now = Time.now
40
+ yield
41
+ benchmark = Time.now - now
42
+ print " (scheduling took #{benchmark}s)"
43
+ if benchmark > TRIGGER_DELAY
44
+ puts "\nTEST RESULT INVALID/UNRELIABLE"
45
+ puts "Scheduling took longer than TRIGGER_DELAY (#{TRIGGER_DELAY}s)."
46
+ puts "Increase TRIGGER_DELAY to a value larger than largest scheduling time."
47
+ end
48
+ end
49
+
50
+ def schedule_unschedule_same_ids_spec (mode)
51
+ scheduler = SCHEDULER_CLASS.start_new
52
+ benchmark { schedule_unschedule(scheduler, mode, NUM_RESCHEDULES) }
53
+ JOB_COUNT.should.satisfy &eventually { scheduler.all_jobs.size }
54
+ JOB_IDS.sort.should.equal(scheduler.find_jobs.map{ |job| job.job_id }.sort)
55
+ JOB_COUNT.should.satisfy &eventually { @trigger_queue.size }
56
+ @trigger_queue.size.should.equal(JOB_COUNT)
57
+ scheduler.stop
58
+ end
59
+
60
+ def schedule_unschedule_unique_ids_spec (mode)
61
+ scheduler = SCHEDULER_CLASS.start_new
62
+ job_ids = []
63
+ benchmark { job_ids = schedule_unschedule(scheduler, mode, NUM_RESCHEDULES, true) }
64
+ JOB_COUNT.should.satisfy &eventually { scheduler.all_jobs.size }
65
+ job_ids.sort.should.equal(scheduler.find_jobs.map{ |job| job.job_id }.sort)
66
+ JOB_COUNT.should.satisfy &eventually { @trigger_queue.size }
67
+ @trigger_queue.size.should.equal(JOB_COUNT)
68
+ scheduler.stop
69
+ end
70
+
71
+ def scheduler_counts(scheduler)
72
+ "all:%d at:%d cron:%d every:%d pending:%d" % [
73
+ scheduler.all_jobs.size,
74
+ scheduler.at_job_count,
75
+ scheduler.cron_job_count,
76
+ scheduler.every_job_count,
77
+ scheduler.pending_job_count]
78
+ end
79
+
80
+ def schedule_unschedule(scheduler, mode, num_reschedules, generate_ids = false)
81
+ job_ids = schedule_jobs(scheduler, mode, generate_ids)
82
+ 1.upto(num_reschedules) do
83
+ unschedule_jobs(scheduler, job_ids)
84
+ job_ids = schedule_jobs(scheduler, mode, generate_ids)
85
+ end
86
+ job_ids
87
+ end
88
+
89
+ def schedule_jobs(scheduler, mode, generate_ids = false)
90
+ job_ids = []
91
+ JOB_IDS.each do |job_id|
92
+ case mode
93
+ when :cron
94
+ job_ids << scheduler.cron("%d * * * * *" % @cron_trigger,
95
+ { :job_id => (generate_ids ? nil : job_id) },
96
+ &@trigger_proc).job_id
97
+ when :at
98
+ job_ids << scheduler.at(@at_trigger,
99
+ { :job_id => (generate_ids ? nil : job_id) },
100
+ &@trigger_proc).job_id
101
+ when :every
102
+ job_ids << scheduler.every(@every_trigger,
103
+ { :job_id => (generate_ids ? nil : job_id) },
104
+ &@trigger_proc).job_id
105
+ else
106
+ raise ArgumentError
107
+ end
108
+ end
109
+ job_ids
110
+ end
111
+
112
+ def unschedule_jobs(scheduler, job_ids)
113
+ job_ids.each { |job_id| scheduler.unschedule(job_id) }
114
+ end
115
+
116
+ # the actual tests
117
+
118
+ before do #(:each) do
119
+ @trigger_queue = Queue.new
120
+ @cron_trigger = ((Time.now.to_i%60) + TRIGGER_DELAY) % 60 # 30 seconds from now
121
+ @at_trigger = Time.now + TRIGGER_DELAY
122
+ @every_trigger = "#{TRIGGER_DELAY}s"
123
+ @trigger_proc = lambda { |job| @trigger_queue << job.job_id }
124
+ end
125
+
126
+ after do #(:each) do
127
+ @trigger_queue = nil
128
+ end
129
+
130
+ it "should sustain frequent schedule/unschedule 'cron' jobs with same ids" do
131
+ schedule_unschedule_same_ids_spec(:cron)
132
+ end
133
+
134
+ it "should sustain frequent schedule/unschedule 'at' jobs with same ids" do
135
+ schedule_unschedule_same_ids_spec(:at)
136
+ end
137
+
138
+ it "should sustain frequent schedule/unschedule 'every' jobs same ids" do
139
+ schedule_unschedule_same_ids_spec(:every)
140
+ end
141
+
142
+ it "should sustain frequent schedule/unschedule 'cron' jobs with unique ids" do
143
+ schedule_unschedule_unique_ids_spec(:cron)
144
+ end
145
+
146
+ it "should sustain frequent schedule/unschedule 'at' jobs with unique ids" do
147
+ schedule_unschedule_unique_ids_spec(:at)
148
+ end
149
+
150
+ it "should sustain frequent schedule/unschedule 'every' jobs unique ids" do
151
+ schedule_unschedule_unique_ids_spec(:every)
152
+ end
153
+
154
+ end
155
+
@@ -0,0 +1,125 @@
1
+
2
+ #
3
+ # Specifying rufus-scheduler
4
+ #
5
+ # Sun May 3 15:44:28 JST 2009
6
+ #
7
+
8
+ require File.dirname(__FILE__) + '/spec_base'
9
+
10
+
11
+ describe "#{SCHEDULER_CLASS} timeouts" do
12
+
13
+ before do
14
+ @s = start_scheduler
15
+ end
16
+ after do
17
+ stop_scheduler(@s)
18
+ end
19
+
20
+ it 'should should refuse 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(ArgumentError)
26
+ end
27
+
28
+ it 'should schedule 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.equal(1)
35
+
36
+ # the timeout job is left
37
+
38
+ sleep 2
39
+ @s.jobs.size.should.equal(1)
40
+ @s.find_by_tag('timeout').size.should.equal(1)
41
+ end
42
+
43
+ it 'should time 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.be.nil
60
+ @s.jobs.size.should.equal(0)
61
+ timedout.should.be.true
62
+ end
63
+
64
+ it 'should die 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.be.true
80
+ @s.jobs.size.should.equal(0)
81
+ timedout.should.be.false
82
+ end
83
+
84
+ it 'should 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
98
+
99
+ timeouts.size.should.equal(3)
100
+ timeouts.each { |to| (to * 10).to_i.should.equal(16) }
101
+ end
102
+
103
+ it 'should point 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.equal('nada')
112
+ end
113
+
114
+ it 'should 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.equal(0)
123
+ end
124
+ end
125
+
@@ -0,0 +1,97 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{tanzeeb-rufus-scheduler}
8
+ s.version = "2.0.7.2"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["John Mettraux", "Tanzeeb Khalili", "Matt Briggs", "Sean Kirby"]
12
+ s.date = %q{2010-11-02}
13
+ s.description = %q{
14
+ job scheduler for Ruby (at, cron, in and every jobs).
15
+
16
+ By default uses a Ruby thread, if EventMachine is present, it will rely on it.
17
+
18
+ This fork adds timezone support to cron schedules.
19
+ }
20
+ s.email = %q{tanzeeb@gmail.com}
21
+ s.extra_rdoc_files = [
22
+ "LICENSE.txt",
23
+ "README.rdoc"
24
+ ]
25
+ s.files = [
26
+ ".gitignore",
27
+ "CHANGELOG.txt",
28
+ "CREDITS.txt",
29
+ "LICENSE.txt",
30
+ "README.rdoc",
31
+ "Rakefile",
32
+ "TODO.txt",
33
+ "lib/rufus-scheduler.rb",
34
+ "lib/rufus/otime.rb",
35
+ "lib/rufus/sc/cronline.rb",
36
+ "lib/rufus/sc/jobqueues.rb",
37
+ "lib/rufus/sc/jobs.rb",
38
+ "lib/rufus/sc/rtime.rb",
39
+ "lib/rufus/sc/scheduler.rb",
40
+ "lib/rufus/sc/version.rb",
41
+ "lib/rufus/scheduler.rb",
42
+ "misc/cronline_next_time_cost.rb",
43
+ "spec/at_in_spec.rb",
44
+ "spec/at_spec.rb",
45
+ "spec/blocking_spec.rb",
46
+ "spec/cron_spec.rb",
47
+ "spec/cronline_spec.rb",
48
+ "spec/every_spec.rb",
49
+ "spec/exception_spec.rb",
50
+ "spec/in_spec.rb",
51
+ "spec/rtime_spec.rb",
52
+ "spec/schedulable_spec.rb",
53
+ "spec/scheduler_spec.rb",
54
+ "spec/spec.rb",
55
+ "spec/spec_base.rb",
56
+ "spec/stress_schedule_unschedule_spec.rb",
57
+ "spec/timeout_spec.rb",
58
+ "tanzeeb-rufus-scheduler.gemspec",
59
+ "test/kjw.rb",
60
+ "test/t.rb"
61
+ ]
62
+ s.homepage = %q{http://github.com/tanzeeb/rufus-scheduler/}
63
+ s.rdoc_options = ["--charset=UTF-8"]
64
+ s.require_paths = ["lib"]
65
+ s.rubyforge_project = %q{rufus}
66
+ s.rubygems_version = %q{1.3.6}
67
+ s.summary = %q{job scheduler for Ruby (at, cron, in and every jobs)}
68
+ s.test_files = [
69
+ "spec/spec.rb"
70
+ ]
71
+
72
+ if s.respond_to? :specification_version then
73
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
74
+ s.specification_version = 3
75
+
76
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
77
+ s.add_development_dependency(%q<rake>, [">= 0"])
78
+ s.add_development_dependency(%q<yard>, [">= 0"])
79
+ s.add_development_dependency(%q<bacon>, [">= 0"])
80
+ s.add_development_dependency(%q<jeweler>, [">= 0"])
81
+ s.add_runtime_dependency(%q<tzinfo>, [">= 0"])
82
+ else
83
+ s.add_dependency(%q<rake>, [">= 0"])
84
+ s.add_dependency(%q<yard>, [">= 0"])
85
+ s.add_dependency(%q<bacon>, [">= 0"])
86
+ s.add_dependency(%q<jeweler>, [">= 0"])
87
+ s.add_dependency(%q<tzinfo>, [">= 0"])
88
+ end
89
+ else
90
+ s.add_dependency(%q<rake>, [">= 0"])
91
+ s.add_dependency(%q<yard>, [">= 0"])
92
+ s.add_dependency(%q<bacon>, [">= 0"])
93
+ s.add_dependency(%q<jeweler>, [">= 0"])
94
+ s.add_dependency(%q<tzinfo>, [">= 0"])
95
+ end
96
+ end
97
+
@@ -0,0 +1,113 @@
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
+