rufus-scheduler 1.0.14 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.txt +2 -82
- data/CREDITS.txt +8 -2
- data/README.rdoc +359 -0
- data/TODO.txt +51 -0
- data/lib/rufus-scheduler.rb +1 -1
- data/lib/rufus/otime.rb +1 -1
- data/lib/rufus/{scheduler → sc}/cronline.rb +44 -80
- data/lib/rufus/sc/jobqueues.rb +157 -0
- data/lib/rufus/sc/jobs.rb +339 -0
- data/lib/rufus/{scheduler/otime.rb → sc/rtime.rb} +35 -45
- data/lib/rufus/sc/scheduler.rb +454 -0
- data/lib/rufus/scheduler.rb +53 -1
- data/spec/spec.rb +14 -0
- metadata +14 -11
- data/README.txt +0 -118
- data/lib/rufus/scheduler/jobs.rb +0 -334
- data/lib/rufus/scheduler/scheduler.rb +0 -1082
- data/test/test.rb +0 -20
data/CHANGELOG.txt
CHANGED
@@ -2,87 +2,7 @@
|
|
2
2
|
= rufus-scheduler CHANGELOG.txt
|
3
3
|
|
4
4
|
|
5
|
-
== rufus-scheduler -
|
5
|
+
== rufus-scheduler - 2.0.0 released 2009/05/07
|
6
6
|
|
7
|
-
-
|
8
|
-
Fixed by Klaas Jan Wierenga
|
9
|
-
|
10
|
-
|
11
|
-
== rufus-scheduler - 1.0.13 released 2009/02/02
|
12
|
-
|
13
|
-
- todo #23779 : removed lib/openwfe/ and restructured to lib/rufus/scheduler/
|
14
|
-
- todo #23774 : adapted to Ruby 1.9.1
|
15
|
-
- todo #23483 : removed gemspec from Rakefile
|
16
|
-
- bug #23458 : :timeout not working on JRuby (reported by Chris Evans). Fixed.
|
17
|
-
- patch #23430 : gemspec patch by Ryan Sonnek
|
18
|
-
- patch #23412 : faster CronLine#next_time patch by TobyH
|
19
|
-
|
20
|
-
|
21
|
-
== rufus-scheduler - 1.0.12 released 2008/12/18
|
22
|
-
|
23
|
-
- todo #23257 : added :timeout parameter for cron/in/at/every
|
24
|
-
- bug #22546 : added note about CronLine#next_time, K Liu
|
25
|
-
- todo #22489 : find_jobs(tag=nil) patch by Xianhang Zhang
|
26
|
-
|
27
|
-
|
28
|
-
== rufus-scheduler - 1.0.11 released 2008/09/03
|
29
|
-
|
30
|
-
- todo #21781 : added lib/rufus-scheduler.rb to make Railsists' lives easier
|
31
|
-
|
32
|
-
|
33
|
-
== rufus-scheduler - 1.0.10 released 2008/08/28
|
34
|
-
|
35
|
-
- todo #21357 : added Rufus::Scheduler::VERSION
|
36
|
-
- bug #21358 : start_new() not accepting parameters. Fixed.
|
37
|
-
|
38
|
-
|
39
|
-
== rufus-scheduler - 1.0.9 released 2008/07/18
|
40
|
-
|
41
|
-
- bug #21262 : brought back (proxy) duration_to_f to Rufus::Scheduler
|
42
|
-
- todo #21251 : added 'at', 'cron', 'in' and 'every' shortcut methods
|
43
|
-
- todo #21203 : keeping track of At and EveryJob until last trigger is over
|
44
|
-
- todo #20823 : now raising exception in case of bad 'at' parameter
|
45
|
-
- todo #21194 : added trigger_thread to Job class
|
46
|
-
- todo #21193 : spinned CronLine out to rufus/cronline.rb
|
47
|
-
- bug #20893 : sometimes unschedule(every_job) not working when job was
|
48
|
-
active (performing). Fixed.
|
49
|
-
|
50
|
-
|
51
|
-
== rufus-scheduler - 1.0.7 released 2008/06/16
|
52
|
-
|
53
|
-
- todo #20669 : implemented CronJob.next_time()
|
54
|
-
- todo #20667 : now passing params to schedule() blocks as well.
|
55
|
-
- bug #20648 : find_schedulable(tag) broken. Fixed.
|
56
|
-
|
57
|
-
|
58
|
-
== rufus-scheduler - 1.0.6 released 2008/05/02
|
59
|
-
|
60
|
-
- bug #20476 : no cron jobs on sundays (wday == 0). Fixed.
|
61
|
-
(thanks to Manfred Usselmann)
|
62
|
-
- todo #19619 : added :thread_name options to Scheduler.new
|
63
|
-
- source moved to http://github.com/jmettraux/rufus-scheduler
|
64
|
-
|
65
|
-
|
66
|
-
== rufus-scheduler - 1.0.5 released 2008/03/17
|
67
|
-
|
68
|
-
- bug #18363 : constrained precision to 0.0 < p <= 1.0 - s188
|
69
|
-
- todo #18821 : best effort drift correction integrated - s187
|
70
|
-
- bug #18513 : 0 seconds and :drop_seconds => "0m". Fixed - s186
|
71
|
-
|
72
|
-
|
73
|
-
== rufus-scheduler - 1.0.4 released 2008/02/29
|
74
|
-
|
75
|
-
- todo #18474 : implemented to_duration_array() - s183
|
76
|
-
- todo #18472 : added Rufus::to_time_string - s181
|
77
|
-
|
78
|
-
|
79
|
-
== rufus-scheduler - 1.0.2 released 2008/01/26
|
80
|
-
|
81
|
-
- patch #17505 : added params :first_at and :first_in for schedule_every()
|
82
|
-
a patch by John Didion - s115
|
83
|
-
|
84
|
-
|
85
|
-
== rufus-scheduler - 1.0 released 2008/01/24
|
86
|
-
|
87
|
-
- initial release after "openwferu-scheduler" - 0.9.16
|
7
|
+
- initial release
|
88
8
|
|
data/CREDITS.txt
CHANGED
@@ -1,15 +1,16 @@
|
|
1
1
|
|
2
2
|
= CREDITS.txt
|
3
3
|
|
4
|
+
|
4
5
|
== Contributors
|
5
6
|
|
6
|
-
- Klaas Jan Wierenga, at/every/in stress tests
|
7
|
+
- Klaas Jan Wierenga, at/every/in stress tests (1.0 and 2.0)
|
7
8
|
- TobyH (http://github.com/tobyh), faster and cleaner CronLine#next_time
|
8
|
-
- Ryan Sonnek (http://github.com/wireframe), gemspec
|
9
9
|
|
10
10
|
|
11
11
|
== Feedback
|
12
12
|
|
13
|
+
- Kenneth Kalmer (daemon-kit)
|
13
14
|
- Chris Evans, :timeout tests on JRuby
|
14
15
|
- Tim Uckun, :timeout concept
|
15
16
|
- K Liu, for the note about CronLine#next_time
|
@@ -23,3 +24,8 @@
|
|
23
24
|
* many people gave feedback previously, see
|
24
25
|
http://openwferu.rubyforge.org/svn/trunk/openwfe-ruby/CREDITS.txt
|
25
26
|
|
27
|
+
|
28
|
+
== and finally
|
29
|
+
|
30
|
+
- many thanks to the EventMachine team (especially Aman Gupta)
|
31
|
+
|
data/README.rdoc
ADDED
@@ -0,0 +1,359 @@
|
|
1
|
+
|
2
|
+
= rufus-scheduler
|
3
|
+
|
4
|
+
rufus-scheduler is a Ruby gem for scheduling pieces of code (jobs). It understands running a job AT a certain time, IN a certain time, EVERY x time or simply via a CRON statement.
|
5
|
+
|
6
|
+
rufus-scheduler is no replacement for cron/at since it runs inside of Ruby.
|
7
|
+
|
8
|
+
|
9
|
+
== alternatives / complements
|
10
|
+
|
11
|
+
A list of related Ruby projects :
|
12
|
+
|
13
|
+
http://github.com/javan/whenever
|
14
|
+
http://github.com/yakischloba/em-timers/
|
15
|
+
|
16
|
+
More like complements :
|
17
|
+
|
18
|
+
http://github.com/mojombo/chronic/
|
19
|
+
http://github.com/hpoydar/chronic_duration
|
20
|
+
|
21
|
+
|
22
|
+
== installation
|
23
|
+
|
24
|
+
sudo gem install rufus-scheduler
|
25
|
+
|
26
|
+
|
27
|
+
== usage
|
28
|
+
|
29
|
+
The usage is similar to the one of the old rufus-scheduler. There are a few differences though.
|
30
|
+
|
31
|
+
require 'rubygems'
|
32
|
+
require 'rufus/scheduler'
|
33
|
+
|
34
|
+
scheduler = Rufus::Scheduler.start_new
|
35
|
+
|
36
|
+
scheduler.in '20m' do
|
37
|
+
puts "order ristretto"
|
38
|
+
end
|
39
|
+
|
40
|
+
scheduler.at 'Thu Mar 26 07:31:43 +0900 2009' do
|
41
|
+
puts 'order pizza'
|
42
|
+
end
|
43
|
+
|
44
|
+
scheduler.cron '0 22 * * 1-5' do
|
45
|
+
# every day of the week at 00:22
|
46
|
+
puts 'activate security system'
|
47
|
+
end
|
48
|
+
|
49
|
+
scheduler.every '5m' do
|
50
|
+
puts 'check blood pressure'
|
51
|
+
end
|
52
|
+
|
53
|
+
# ...
|
54
|
+
|
55
|
+
scheduler.stop
|
56
|
+
|
57
|
+
|
58
|
+
This code summons a plain version of the scheduler, this can be made more explicit via :
|
59
|
+
|
60
|
+
scheduler = Rufus::Scheduler::PlainScheduler.start_new
|
61
|
+
|
62
|
+
This PlainScheduler accepts a :thread_name option :
|
63
|
+
|
64
|
+
scheduler = Rufus::Scheduler::PlainScheduler.start_new(:thread_name => 'my scheduler')
|
65
|
+
|
66
|
+
might be helpful when tracking threads.
|
67
|
+
|
68
|
+
|
69
|
+
Note that is there is EventMachine present and running,
|
70
|
+
|
71
|
+
scheduler = Rufus::Scheduler.start_new
|
72
|
+
|
73
|
+
will return an instance of Rufus::Scheduler::EmScheduler (leveraging EventMachine).
|
74
|
+
|
75
|
+
|
76
|
+
== block parameters
|
77
|
+
|
78
|
+
Scheduled blocks accept 0 or 1 parameter (this unique parameter is the job
|
79
|
+
instance itself).
|
80
|
+
|
81
|
+
scheduler.every '5m' do
|
82
|
+
puts 'check blood pressure'
|
83
|
+
end
|
84
|
+
scheduler.every '1y' do |job|
|
85
|
+
puts "check cholesterol levels (#{job.job_id})"
|
86
|
+
end
|
87
|
+
|
88
|
+
See the class Job for more details :
|
89
|
+
|
90
|
+
http://rufus.rubyforge.org/rufus-scheduler/classes/Rufus/Scheduler/Job.html
|
91
|
+
|
92
|
+
|
93
|
+
== the time strings understood by rufus-scheduler
|
94
|
+
|
95
|
+
require 'rubygems'
|
96
|
+
require 'rufus/scheduler'
|
97
|
+
|
98
|
+
p Rufus.parse_time_string '500' # => 0.5
|
99
|
+
p Rufus.parse_time_string '1000' # => 1.0
|
100
|
+
p Rufus.parse_time_string '1h' # => 3600.0
|
101
|
+
p Rufus.parse_time_string '1h10s' # => 3610.0
|
102
|
+
p Rufus.parse_time_string '1w2d' # => 777600.0
|
103
|
+
|
104
|
+
p Rufus.to_time_string 60 # => "1m"
|
105
|
+
p Rufus.to_time_string 3661 # => "1h1m1s"
|
106
|
+
p Rufus.to_time_string 7 * 24 * 3600 # => "1w"
|
107
|
+
|
108
|
+
|
109
|
+
== :blocking
|
110
|
+
|
111
|
+
Jobs will, by default, trigger in their own thread. This is usually desirable since one expects the scheduler to continue scheduling even if a job is currently running.
|
112
|
+
|
113
|
+
Jobs scheduled with the :blocking parameter will run in the thread of the scheduler, blocking it.
|
114
|
+
|
115
|
+
scheduler.in '20m', :blocking => true do
|
116
|
+
puts "order ristretto"
|
117
|
+
sleep 2 * 60
|
118
|
+
end
|
119
|
+
scheduler.in '21m' do
|
120
|
+
puts "order espresso"
|
121
|
+
end
|
122
|
+
|
123
|
+
Hence, our espresso wil come in 22 minutes instead of 21.
|
124
|
+
|
125
|
+
|
126
|
+
== 'every' jobs and :first_at / :first_in
|
127
|
+
|
128
|
+
This job will execute every 3 days, but first time will be in 5 days from now :
|
129
|
+
|
130
|
+
scheduler.every '3d', :first_in => '5d' do
|
131
|
+
# do something
|
132
|
+
end
|
133
|
+
|
134
|
+
This job will execute every 3 days, starting from Christmas Eve at noon :
|
135
|
+
|
136
|
+
scheduler.every '3d', :first_at => '2009/12/24 12:00' do
|
137
|
+
# do something
|
138
|
+
end
|
139
|
+
|
140
|
+
The chronic gem may help (http://chronic.rubyforge.org/) :
|
141
|
+
|
142
|
+
require 'chronic' # sudo gem install chronic
|
143
|
+
|
144
|
+
scheduler.every '3h', :first_at => Chronic.parse('this tuesday 5:00') do
|
145
|
+
# do something starting this tueday
|
146
|
+
end
|
147
|
+
|
148
|
+
|
149
|
+
== self unschedule for 'cron' and 'every' jobs
|
150
|
+
|
151
|
+
'at' and 'in' jobs fire once only. 'cron' and 'every' jobs do fire repeatedly, so it might be useful to stop them.
|
152
|
+
|
153
|
+
scheduler.every '3d' do |job|
|
154
|
+
l = determine_crop_maturity_level()
|
155
|
+
if l >= 7
|
156
|
+
puts "crop is ready."
|
157
|
+
job.unschedule
|
158
|
+
else
|
159
|
+
puts "crop not yet ready..."
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
In this example, the 'every' job will unschedule itself when the crop is ready.
|
164
|
+
|
165
|
+
|
166
|
+
== schedulables
|
167
|
+
|
168
|
+
Sometimes passing a block isn't that convenient :
|
169
|
+
|
170
|
+
class JobThing
|
171
|
+
def initialize (relevant_info)
|
172
|
+
@ri = relevant_info
|
173
|
+
end
|
174
|
+
def call (job)
|
175
|
+
do_something_about_it
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
# ...
|
180
|
+
|
181
|
+
scheduler.in '3d', JobThing.new('http://news.example.com/data_xyz')
|
182
|
+
scheduler.in '1w', JobThing.new('http://news.example.com/data_abc'), :timeout => '1d'
|
183
|
+
|
184
|
+
rufus-scheduler accepts anything that responds to a call method with a unique parameter (it will pass the job) as a 'schedulable'.
|
185
|
+
|
186
|
+
|
187
|
+
== looking up jobs
|
188
|
+
|
189
|
+
scheduler.jobs
|
190
|
+
# returns a map job_id => job of at/in/every jobs
|
191
|
+
|
192
|
+
scheduler.cron_jobs
|
193
|
+
# idem for cron jobs
|
194
|
+
|
195
|
+
scheduler.all_jobs
|
196
|
+
# idem but for every/at/in/cron jobs (all of them)
|
197
|
+
|
198
|
+
scheduler.find_by_tag(t)
|
199
|
+
# returns all the jobs with a given tag (passed at schedule time with :tags)
|
200
|
+
|
201
|
+
|
202
|
+
== unscheduling jobs
|
203
|
+
|
204
|
+
The 'scheduling' methods always return an instance of Rufus::Scheduler::Job. This object can be used for unscheduling :
|
205
|
+
|
206
|
+
job = scheduler.in '2d', :tags => 'admin' do
|
207
|
+
run_backlog_cleaning()
|
208
|
+
end
|
209
|
+
|
210
|
+
# later ...
|
211
|
+
|
212
|
+
job.unschedule
|
213
|
+
# or
|
214
|
+
scheduler.unschedule(job.job_id)
|
215
|
+
|
216
|
+
|
217
|
+
== tags
|
218
|
+
|
219
|
+
You can specify tags at schedule time :
|
220
|
+
|
221
|
+
scheduler.in '2d', :tags => 'admin' do
|
222
|
+
run_backlog_cleaning()
|
223
|
+
end
|
224
|
+
scheduler.every '3m', :tags => 'production' do
|
225
|
+
check_order_log()
|
226
|
+
end
|
227
|
+
|
228
|
+
And later query the scheduler for those jobs :
|
229
|
+
|
230
|
+
admin_jobs = scheduler.find_by_tag('admin')
|
231
|
+
production_jobs = scheduler.find_by_tag('production')
|
232
|
+
|
233
|
+
|
234
|
+
== timeout
|
235
|
+
|
236
|
+
One can specify a timeout for the triggering of a job.
|
237
|
+
|
238
|
+
scheduler.every '2d', :timeout => '40m' do
|
239
|
+
begin
|
240
|
+
run_backlog_cleaning()
|
241
|
+
rescue Rufus::Scheduler::TimeOutError => toe
|
242
|
+
# timeout occurred
|
243
|
+
end
|
244
|
+
end
|
245
|
+
|
246
|
+
This job will run every two days. If a run takes more than 40 minutes it will timeout (its thread will receive a TimeOutError).
|
247
|
+
|
248
|
+
This timeout feature relies on an 'in' job scheduled at the moment the main job gets triggered, hence the '40m' time string format.
|
249
|
+
|
250
|
+
|
251
|
+
== exceptions in jobs
|
252
|
+
|
253
|
+
By default, when exception occur when a job performs, the error message will be output to the STDOUT.
|
254
|
+
|
255
|
+
It's easy to customize that behaviour :
|
256
|
+
|
257
|
+
scheduler = Rufus::Scheduler::PlainScheduler.start_new
|
258
|
+
# or
|
259
|
+
#scheduler = Rufus::Scheduler::EmScheduler.start_new
|
260
|
+
|
261
|
+
def scheduler.handle_exception (job, exception)
|
262
|
+
puts "job #{job.job_id} caught exception '#{exception}'"
|
263
|
+
end
|
264
|
+
|
265
|
+
For backward compatibility, overriding #log_exception is still OK :
|
266
|
+
|
267
|
+
def scheduler.log_exception (exception)
|
268
|
+
puts "caught exception '#{exception}'"
|
269
|
+
end
|
270
|
+
|
271
|
+
Note that an every job or a cron job will stay scheduled even if it experiences an exception.
|
272
|
+
|
273
|
+
|
274
|
+
== frequency
|
275
|
+
|
276
|
+
The default frequency for the scheduler is 0.330 seconds. This means that the usual scheduler implementation will wake up, trigger jobs that are to be triggered and then go back to sleep for 0.330 seconds. Note that this doesn't mean that the scheduler will wake up very 0.330 seconds (checking and triggering do take time).
|
277
|
+
|
278
|
+
You can set a different frequency when starting / initializing the scheduler :
|
279
|
+
|
280
|
+
require 'rubygems'
|
281
|
+
require 'rufus/scheduler'
|
282
|
+
|
283
|
+
scheduler = Rufus::Scheduler.start_new(:frequency => 60.0)
|
284
|
+
# for a lazy scheduler that only wakes up every 60 seconds
|
285
|
+
|
286
|
+
|
287
|
+
== usage with EventMachine
|
288
|
+
|
289
|
+
rufus-scheduler 2.0 can be used in conjunction with EventMachine (http://github.com/eventmachine/eventmachine/).
|
290
|
+
|
291
|
+
More and more ruby applications are using EventMachine. This flavour of the scheduler relies on EventMachine, thus it doesn't require a separate thread like the PlainScheduler does.
|
292
|
+
|
293
|
+
require 'rubygems'
|
294
|
+
require 'eventmachine'
|
295
|
+
|
296
|
+
EM.run {
|
297
|
+
|
298
|
+
scheduler = Rufus::Scheduler::EmScheduler.start_new
|
299
|
+
|
300
|
+
scheduler.in '20m' do
|
301
|
+
puts "order ristretto"
|
302
|
+
end
|
303
|
+
}
|
304
|
+
|
305
|
+
|
306
|
+
== tested with
|
307
|
+
|
308
|
+
ruby 1.8.6, ruby 1.9.1p0
|
309
|
+
on jruby 1.2.0 it has some tiny issues (spec/blocking_spec.rb)
|
310
|
+
|
311
|
+
|
312
|
+
== dependencies
|
313
|
+
|
314
|
+
the ruby gem 'eventmachine' if you use Rufus::Scheduler::EmScheduler, else no other dependencies.
|
315
|
+
|
316
|
+
|
317
|
+
== mailing list
|
318
|
+
|
319
|
+
On the rufus-ruby list :
|
320
|
+
|
321
|
+
http://groups.google.com/group/rufus-ruby
|
322
|
+
|
323
|
+
|
324
|
+
== issue tracker
|
325
|
+
|
326
|
+
http://rubyforge.org/tracker/?atid=18584&group_id=4812&func=browse
|
327
|
+
|
328
|
+
|
329
|
+
== irc
|
330
|
+
|
331
|
+
irc.freenode.net #ruote
|
332
|
+
|
333
|
+
|
334
|
+
== source
|
335
|
+
|
336
|
+
http://github.com/jmettraux/rufus-scheduler
|
337
|
+
|
338
|
+
git clone git://github.com/jmettraux/rufus-scheduler.git
|
339
|
+
|
340
|
+
|
341
|
+
== credits
|
342
|
+
|
343
|
+
http://github.com/jmettraux/rufus-scheduler/blob/master/CREDITS.txt
|
344
|
+
|
345
|
+
|
346
|
+
== authors
|
347
|
+
|
348
|
+
John Mettraux, jmettraux@gmail.com, http://jmettraux.wordpress.com
|
349
|
+
|
350
|
+
|
351
|
+
== the rest of Rufus
|
352
|
+
|
353
|
+
http://rufus.rubyforge.org
|
354
|
+
|
355
|
+
|
356
|
+
== license
|
357
|
+
|
358
|
+
MIT
|
359
|
+
|