rufus-scheduler 2.0.6 → 2.0.7

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,2 @@
1
+ .rvmrc
2
+ rdoc
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --colour --format documentation
@@ -2,6 +2,12 @@
2
2
  = rufus-scheduler CHANGELOG.txt
3
3
 
4
4
 
5
+ == rufus-scheduler - 2.0.7 released 2010/11/09
6
+
7
+ - cron and timezones, thanks Tanzeeb Khalili
8
+ - Scheduler#trigger_threads, thanks Tim Uckun
9
+
10
+
5
11
  == rufus-scheduler - 2.0.6 released 2010/05/01
6
12
 
7
13
  - timeout jobs not outliving their parent job anymore, thanks Joel Wood
@@ -4,6 +4,8 @@
4
4
 
5
5
  == Contributors
6
6
 
7
+ - Tanzeeb Khalili (http://github.com/tanzeeb) cron and timezones
8
+ - Adam Davies (http://github.com/adz), @allow_overlap = false
7
9
  - Klaas Jan Wierenga, at/every/in stress tests (1.0 and 2.0)
8
10
  - TobyH (http://github.com/tobyh), faster and cleaner CronLine#next_time
9
11
 
@@ -10,13 +10,14 @@ rufus-scheduler is no replacement for cron/at since it runs inside of Ruby.
10
10
 
11
11
  A list of related Ruby projects :
12
12
 
13
- http://github.com/javan/whenever
14
- http://github.com/yakischloba/em-timers/
13
+ * http://github.com/javan/whenever
14
+ * http://github.com/yakischloba/em-timers
15
+ * http://github.com/adamwiggins/clockwork
15
16
 
16
17
  More like complements :
17
18
 
18
- http://github.com/mojombo/chronic/
19
- http://github.com/hpoydar/chronic_duration
19
+ * http://github.com/mojombo/chronic
20
+ * http://github.com/hpoydar/chronic_duration
20
21
 
21
22
 
22
23
  == installation
@@ -69,6 +70,32 @@ Note that is there is EventMachine present and running,
69
70
  will return an instance of Rufus::Scheduler::EmScheduler (leveraging EventMachine).
70
71
 
71
72
 
73
+ == a note about cron jobs
74
+
75
+ This is a classical cron :
76
+
77
+ scheduler.cron '0 22 * * 1-5' do
78
+ # every day of the week at 22:00 (10pm)
79
+ end
80
+
81
+ Rufus-scheduler supports two variants to that notation : seconds and timezones.
82
+
83
+ scheduler.cron '13 0 22 * * 1-5' do
84
+ # every day of the week at 22:00:13
85
+ end
86
+
87
+ scheduler.cron '0 22 * * 1-5 Europe/Paris' do
88
+ # every day of the week when it's 22:00 in Paris
89
+ end
90
+ scheduler.cron '0 22 * * 1-5 Etc/GMT+2' do
91
+ # every day of the week when it's 22:00 in GMT+2
92
+ end
93
+
94
+ The timezones are the ones supported by the 'tzinfo' rubygem (http://tzinfo.rubyforge.org/).
95
+
96
+ The timezone support was contributed by Tanzeeb Khalili.
97
+
98
+
72
99
  == scheduler.join
73
100
 
74
101
  Note that if you have a tiny script like this one :
@@ -187,10 +214,10 @@ In this example, the 'every' job will unschedule itself when the crop is ready.
187
214
  Sometimes passing a block isn't that convenient :
188
215
 
189
216
  class JobThing
190
- def initialize (relevant_info)
217
+ def initialize(relevant_info)
191
218
  @ri = relevant_info
192
219
  end
193
- def call (job)
220
+ def call(job)
194
221
  do_something_about_it
195
222
  end
196
223
  end
@@ -205,7 +232,7 @@ rufus-scheduler accepts anything that responds to a call method with a unique pa
205
232
  For compatibility with older (1.x) versions, schedulables with a trigger methods are accepted :
206
233
 
207
234
  class JobThing
208
- def trigger (params)
235
+ def trigger(params)
209
236
  job = params[:job]
210
237
  end
211
238
  end
@@ -287,13 +314,13 @@ It's easy to customize that behaviour :
287
314
  # or
288
315
  #scheduler = Rufus::Scheduler::EmScheduler.start_new
289
316
 
290
- def scheduler.handle_exception (job, exception)
317
+ def scheduler.handle_exception(job, exception)
291
318
  puts "job #{job.job_id} caught exception '#{exception}'"
292
319
  end
293
320
 
294
321
  For backward compatibility, overriding #log_exception is still OK :
295
322
 
296
- def scheduler.log_exception (exception)
323
+ def scheduler.log_exception(exception)
297
324
  puts "caught exception '#{exception}'"
298
325
  end
299
326
 
@@ -334,13 +361,19 @@ More and more ruby applications are using EventMachine. This flavour of the sche
334
361
 
335
362
  == tested with
336
363
 
337
- ruby 1.8.6, ruby 1.9.1p0
338
- on jruby 1.2.0 it has some tiny issues (spec/blocking_spec.rb)
364
+ * 1.8.7-p249
365
+ * 1.9.1-p378
366
+ * 1.9.2-p0
367
+ * jruby-1.5.1
368
+
369
+ on Mac OS X (Snow Leopard).
339
370
 
340
371
 
341
372
  == dependencies
342
373
 
343
- the ruby gem 'eventmachine' if you use Rufus::Scheduler::EmScheduler, else no other dependencies.
374
+ The 'tzinfo' rubygem.
375
+
376
+ The ruby gem 'eventmachine' if you use Rufus::Scheduler::EmScheduler, else no other dependencies.
344
377
 
345
378
 
346
379
  == mailing list
data/Rakefile CHANGED
@@ -10,8 +10,18 @@ load 'lib/rufus/sc/version.rb'
10
10
  # CLEAN
11
11
 
12
12
  require 'rake/clean'
13
- CLEAN.include('pkg', 'tmp', 'html')
14
- task :default => [ :clean ]
13
+ CLEAN.include('pkg', 'tmp', 'rdoc')
14
+
15
+
16
+ #
17
+ # TEST / SPEC
18
+
19
+ task :spec do
20
+ sh 'rspec spec/'
21
+ end
22
+ task :test => :spec
23
+
24
+ task :default => :spec
15
25
 
16
26
 
17
27
  #
@@ -35,12 +45,11 @@ Jeweler::Tasks.new do |gem|
35
45
  gem.authors = [ 'John Mettraux' ]
36
46
  gem.rubyforge_project = 'rufus'
37
47
 
38
- gem.test_file = 'spec/spec.rb'
48
+ #gem.test_file = 'spec/spec.rb'
39
49
 
40
- #gem.add_dependency 'yajl-ruby'
50
+ gem.add_dependency 'tzinfo'
41
51
  gem.add_development_dependency 'rake'
42
- gem.add_development_dependency 'yard'
43
- gem.add_development_dependency 'bacon'
52
+ gem.add_development_dependency 'rspec'
44
53
  gem.add_development_dependency 'jeweler'
45
54
 
46
55
  # gemspec spec : http://www.rubygems.org/read/chapter/20
@@ -51,33 +60,29 @@ Jeweler::GemcutterTasks.new
51
60
  #
52
61
  # DOC
53
62
 
54
- begin
55
-
56
- require 'yard'
57
-
58
- YARD::Rake::YardocTask.new do |doc|
59
- doc.options = [
60
- '-o', 'html/rufus-scheduler', '--title',
61
- "rufus-scheduler #{Rufus::Scheduler::VERSION}"
62
- ]
63
- end
63
+ #
64
+ # make sure to have rdoc 2.5.x to run that
65
+ #
66
+ require 'rake/rdoctask'
67
+ Rake::RDocTask.new do |rd|
64
68
 
65
- rescue LoadError
69
+ rd.main = 'README.rdoc'
70
+ rd.rdoc_dir = 'rdoc/rufus-scheduler'
71
+ rd.title = "rufus-scheduler #{Rufus::Scheduler::VERSION}"
66
72
 
67
- task :yard do
68
- abort "YARD is not available : sudo gem install yard"
69
- end
73
+ rd.rdoc_files.include(
74
+ 'README.rdoc', 'CHANGELOG.txt', 'LICENSE.txt', 'CREDITS.txt', 'lib/**/*.rb')
70
75
  end
71
76
 
72
77
 
73
78
  #
74
79
  # TO THE WEB
75
80
 
76
- task :upload_website => [ :clean, :yard ] do
81
+ task :upload_rdoc => [ :clean, :rdoc ] do
77
82
 
78
83
  account = 'jmettraux@rubyforge.org'
79
84
  webdir = '/var/www/gforge-projects/rufus'
80
85
 
81
- sh "rsync -azv -e ssh html/rufus-scheduler #{account}:#{webdir}/"
86
+ sh "rsync -azv -e ssh rdoc/rufus-scheduler #{account}:#{webdir}/"
82
87
  end
83
88
 
@@ -22,6 +22,8 @@
22
22
  # Made in Japan.
23
23
  #++
24
24
 
25
+ require 'tzinfo'
26
+
25
27
 
26
28
  module Rufus
27
29
 
@@ -31,20 +33,19 @@ module Rufus
31
33
  #
32
34
  class CronLine
33
35
 
34
- #
35
36
  # The string used for creating this cronline instance.
36
37
  #
37
38
  attr_reader :original
38
39
 
39
- attr_reader \
40
- :seconds,
41
- :minutes,
42
- :hours,
43
- :days,
44
- :months,
45
- :weekdays
40
+ attr_reader :seconds
41
+ attr_reader :minutes
42
+ attr_reader :hours
43
+ attr_reader :days
44
+ attr_reader :months
45
+ attr_reader :weekdays
46
+ attr_reader :timezone
46
47
 
47
- def initialize (line)
48
+ def initialize(line)
48
49
 
49
50
  super()
50
51
 
@@ -52,10 +53,12 @@ module Rufus
52
53
 
53
54
  items = line.split
54
55
 
55
- unless items.length == 5 or items.length == 6
56
- raise(
57
- "cron '#{line}' string should hold 5 or 6 items, not #{items.length}")
58
- end
56
+ @timezone = (TZInfo::Timezone.get(items.last) rescue nil)
57
+ items.pop if @timezone
58
+
59
+ raise ArgumentError.new(
60
+ "not a valid cronline : '#{line}'"
61
+ ) unless items.length == 5 or items.length == 6
59
62
 
60
63
  offset = items.length - 5
61
64
 
@@ -67,13 +70,14 @@ module Rufus
67
70
  @weekdays = parse_weekdays(items[4 + offset])
68
71
  end
69
72
 
70
- #
71
73
  # Returns true if the given time matches this cron line.
72
74
  #
73
- def matches? (time)
75
+ def matches?(time)
74
76
 
75
77
  time = Time.at(time) unless time.kind_of?(Time)
76
78
 
79
+ time = @timezone.utc_to_local(time.getutc) if @timezone
80
+
77
81
  return false unless sub_match?(time.sec, @seconds)
78
82
  return false unless sub_match?(time.min, @minutes)
79
83
  return false unless sub_match?(time.hour, @hours)
@@ -83,17 +87,6 @@ module Rufus
83
87
  true
84
88
  end
85
89
 
86
- #
87
- # Returns an array of 6 arrays (seconds, minutes, hours, days,
88
- # months, weekdays).
89
- # This method is used by the cronline unit tests.
90
- #
91
- def to_array
92
-
93
- [ @seconds, @minutes, @hours, @days, @months, @weekdays ]
94
- end
95
-
96
- #
97
90
  # Returns the next time that this cron line is supposed to 'fire'
98
91
  #
99
92
  # This is raw, 3 secs to iterate over 1 year on my macbook :( brutal.
@@ -107,21 +100,26 @@ module Rufus
107
100
  # be passed if no start time is specified (search start time set to
108
101
  # Time.now))
109
102
  #
110
- # >> Rufus::CronLine.new('30 7 * * *').next_time( Time.mktime(2008,10,24,7,29) )
111
- # => Fri Oct 24 07:30:00 -0500 2008
103
+ # Rufus::CronLine.new('30 7 * * *').next_time(
104
+ # Time.mktime(2008, 10, 24, 7, 29))
105
+ # #=> Fri Oct 24 07:30:00 -0500 2008
112
106
  #
113
- # >> Rufus::CronLine.new('30 7 * * *').next_time( Time.utc(2008,10,24,7,29) )
114
- # => Fri Oct 24 07:30:00 UTC 2008
107
+ # Rufus::CronLine.new('30 7 * * *').next_time(
108
+ # Time.utc(2008, 10, 24, 7, 29))
109
+ # #=> Fri Oct 24 07:30:00 UTC 2008
115
110
  #
116
- # >> Rufus::CronLine.new('30 7 * * *').next_time( Time.utc(2008,10,24,7,29) ).localtime
117
- # => Fri Oct 24 02:30:00 -0500 2008
111
+ # Rufus::CronLine.new('30 7 * * *').next_time(
112
+ # Time.utc(2008, 10, 24, 7, 29)).localtime
113
+ # #=> Fri Oct 24 02:30:00 -0500 2008
118
114
  #
119
115
  # (Thanks to K Liu for the note and the examples)
120
116
  #
121
- def next_time (time=Time.now)
117
+ def next_time(now=Time.now)
118
+
119
+ time = @timezone ? @timezone.utc_to_local(now.getutc) : now
122
120
 
123
- time -= time.usec * 1e-6
124
- time += 1
121
+ time = time - time.usec * 1e-6 + 1
122
+ # little adjustment before starting
125
123
 
126
124
  loop do
127
125
 
@@ -129,17 +127,14 @@ module Rufus
129
127
  time += (24 - time.hour) * 3600 - time.min * 60 - time.sec
130
128
  next
131
129
  end
132
-
133
130
  unless sub_match?(time.hour, @hours)
134
131
  time += (60 - time.min) * 60 - time.sec
135
132
  next
136
133
  end
137
-
138
134
  unless sub_match?(time.min, @minutes)
139
135
  time += 60 - time.sec
140
136
  next
141
137
  end
142
-
143
138
  unless sub_match?(time.sec, @seconds)
144
139
  time += 1
145
140
  next
@@ -148,16 +143,37 @@ module Rufus
148
143
  break
149
144
  end
150
145
 
146
+ if @timezone
147
+ time = @timezone.local_to_utc(time)
148
+ time = time.getlocal unless now.utc?
149
+ end
150
+
151
151
  time
152
152
  end
153
153
 
154
+ # Returns an array of 6 arrays (seconds, minutes, hours, days,
155
+ # months, weekdays).
156
+ # This method is used by the cronline unit tests.
157
+ #
158
+ def to_array
159
+
160
+ [
161
+ @seconds,
162
+ @minutes,
163
+ @hours,
164
+ @days,
165
+ @months,
166
+ @weekdays,
167
+ @timezone ? @timezone.name : nil
168
+ ]
169
+ end
170
+
154
171
  private
155
172
 
156
173
  WDS = %w[ sun mon tue wed thu fri sat ]
157
- #
158
174
  # used by parse_weekday()
159
175
 
160
- def parse_weekdays (item)
176
+ def parse_weekdays(item)
161
177
 
162
178
  item = item.downcase
163
179
 
@@ -170,7 +186,7 @@ module Rufus
170
186
  r
171
187
  end
172
188
 
173
- def parse_item (item, min, max)
189
+ def parse_item(item, min, max)
174
190
 
175
191
  return nil if item == '*'
176
192
  return parse_list(item, min, max) if item.index(',')
@@ -184,14 +200,14 @@ module Rufus
184
200
  [ i ]
185
201
  end
186
202
 
187
- def parse_list (item, min, max)
203
+ def parse_list(item, min, max)
188
204
 
189
205
  item.split(',').inject([]) { |r, i|
190
206
  r.push(parse_range(i, min, max))
191
207
  }.flatten
192
208
  end
193
209
 
194
- def parse_range (item, min, max)
210
+ def parse_range(item, min, max)
195
211
 
196
212
  i = item.index('-')
197
213
  j = item.index('/')
@@ -235,16 +251,17 @@ module Rufus
235
251
  end
236
252
 
237
253
  def sub_match?(value, values)
254
+
238
255
  values.nil? || values.include?(value)
239
256
  end
240
257
 
241
258
  def date_match?(date)
259
+
242
260
  return false unless sub_match?(date.day, @days)
243
261
  return false unless sub_match?(date.month, @months)
244
262
  return false unless sub_match?(date.wday, @weekdays)
245
263
  true
246
264
  end
247
265
  end
248
-
249
266
  end
250
267
 
@@ -63,7 +63,7 @@ module Scheduler
63
63
 
64
64
  # Adds this job to the map.
65
65
  #
66
- def << (job)
66
+ def <<(job)
67
67
 
68
68
  @mutex.synchronize do
69
69
  delete(job.job_id)
@@ -74,7 +74,7 @@ module Scheduler
74
74
 
75
75
  # Removes a job (given its id). Returns nil if the job was not found.
76
76
  #
77
- def unschedule (job_id)
77
+ def unschedule(job_id)
78
78
 
79
79
  @mutex.synchronize { delete(job_id) }
80
80
  end
@@ -88,7 +88,7 @@ module Scheduler
88
88
 
89
89
  # Returns a list of jobs of the given type (:at|:in|:every)
90
90
  #
91
- def select (type)
91
+ def select(type)
92
92
 
93
93
  type = JOB_TYPES[type]
94
94
  @jobs.select { |j| j.is_a?(type) }
@@ -101,7 +101,7 @@ module Scheduler
101
101
 
102
102
  protected
103
103
 
104
- def delete (job_id)
104
+ def delete(job_id)
105
105
 
106
106
  j = @jobs.find { |j| j.job_id == job_id }
107
107
  @jobs.delete(j) if j
@@ -109,7 +109,7 @@ module Scheduler
109
109
 
110
110
  # Returns the next job to trigger. Returns nil if none eligible.
111
111
  #
112
- def job_to_trigger (now)
112
+ def job_to_trigger(now)
113
113
 
114
114
  @mutex.synchronize do
115
115
  if @jobs.size > 0 && now.to_f >= @jobs.first.at
@@ -146,7 +146,7 @@ module Scheduler
146
146
  jobs.each { |job| job.trigger_if_matches(now) }
147
147
  end
148
148
 
149
- def << (job)
149
+ def <<(job)
150
150
 
151
151
  @mutex.synchronize do
152
152
  delete(job.job_id)
@@ -154,7 +154,6 @@ module Scheduler
154
154
  end
155
155
  end
156
156
  end
157
-
158
157
  end
159
158
  end
160
159