rufus-scheduler 2.0.3 → 2.0.4

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.
@@ -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