rufus-scheduler 2.0.3 → 2.0.4

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,103 @@
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
+ end
103
+
data/test/kjw.rb ADDED
@@ -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
+
data/test/t.rb ADDED
@@ -0,0 +1,20 @@
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
+
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rufus-scheduler
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.3
4
+ version: 2.0.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - John Mettraux
@@ -9,10 +9,39 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-11-05 00:00:00 +09:00
12
+ date: 2010-02-12 00:00:00 +09:00
13
13
  default_executable:
14
- dependencies: []
15
-
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: yard
17
+ type: :development
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: "0"
24
+ version:
25
+ - !ruby/object:Gem::Dependency
26
+ name: bacon
27
+ type: :development
28
+ version_requirement:
29
+ version_requirements: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: "0"
34
+ version:
35
+ - !ruby/object:Gem::Dependency
36
+ name: jeweler
37
+ type: :development
38
+ version_requirement:
39
+ version_requirements: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ version: "0"
44
+ version:
16
45
  description: "\n job scheduler for Ruby (at, cron, in and every jobs).\n\n By default uses a Ruby thread, if EventMachine is present, it will rely on it.\n "
17
46
  email: jmettraux@gmail.com
18
47
  executables: []
@@ -20,11 +49,16 @@ executables: []
20
49
  extensions: []
21
50
 
22
51
  extra_rdoc_files:
52
+ - LICENSE.txt
23
53
  - README.rdoc
54
+ files:
24
55
  - CHANGELOG.txt
25
56
  - CREDITS.txt
26
57
  - LICENSE.txt
27
- files:
58
+ - README.rdoc
59
+ - Rakefile
60
+ - TODO.txt
61
+ - lib/rufus-scheduler.rb
28
62
  - lib/rufus/otime.rb
29
63
  - lib/rufus/sc/cronline.rb
30
64
  - lib/rufus/sc/jobqueues.rb
@@ -32,19 +66,32 @@ files:
32
66
  - lib/rufus/sc/rtime.rb
33
67
  - lib/rufus/sc/scheduler.rb
34
68
  - lib/rufus/scheduler.rb
35
- - lib/rufus-scheduler.rb
36
- - CHANGELOG.txt
37
- - CREDITS.txt
38
- - LICENSE.txt
39
- - TODO.txt
40
- - README.rdoc
69
+ - misc/cronline_next_time_cost.rb
70
+ - rufus-scheduler.gemspec
71
+ - spec/at_in_spec.rb
72
+ - spec/at_spec.rb
73
+ - spec/blocking_spec.rb
74
+ - spec/cron_spec.rb
75
+ - spec/cronline_spec.rb
76
+ - spec/every_spec.rb
77
+ - spec/exception_spec.rb
78
+ - spec/in_spec.rb
79
+ - spec/rtime_spec.rb
80
+ - spec/schedulable_spec.rb
81
+ - spec/scheduler_spec.rb
82
+ - spec/spec.rb
83
+ - spec/spec_base.rb
84
+ - spec/stress_schedule_unschedule_spec.rb
85
+ - spec/timeout_spec.rb
86
+ - test/kjw.rb
87
+ - test/t.rb
41
88
  has_rdoc: true
42
- homepage: http://github.com/jmettraux/rufus-scheduler
89
+ homepage: http://github.com/jmettraux/rufus-scheduler/
43
90
  licenses: []
44
91
 
45
92
  post_install_message:
46
- rdoc_options: []
47
-
93
+ rdoc_options:
94
+ - --charset=UTF-8
48
95
  require_paths:
49
96
  - lib
50
97
  required_ruby_version: !ruby/object:Gem::Requirement