rufus-scheduler 2.0.24 → 3.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.txt +6 -0
- data/CREDITS.txt +4 -0
- data/README.md +1064 -0
- data/Rakefile +1 -4
- data/TODO.txt +145 -55
- data/lib/rufus/scheduler.rb +502 -26
- data/lib/rufus/{sc → scheduler}/cronline.rb +46 -17
- data/lib/rufus/{sc/version.rb → scheduler/job_array.rb} +56 -4
- data/lib/rufus/scheduler/jobs.rb +548 -0
- data/lib/rufus/scheduler/util.rb +318 -0
- data/rufus-scheduler.gemspec +30 -4
- data/spec/cronline_spec.rb +29 -8
- data/spec/error_spec.rb +116 -0
- data/spec/job_array_spec.rb +39 -0
- data/spec/job_at_spec.rb +58 -0
- data/spec/job_cron_spec.rb +67 -0
- data/spec/job_every_spec.rb +71 -0
- data/spec/job_in_spec.rb +20 -0
- data/spec/job_interval_spec.rb +68 -0
- data/spec/job_repeat_spec.rb +308 -0
- data/spec/job_spec.rb +387 -115
- data/spec/lockfile_spec.rb +61 -0
- data/spec/parse_spec.rb +203 -0
- data/spec/schedule_at_spec.rb +129 -0
- data/spec/schedule_cron_spec.rb +66 -0
- data/spec/schedule_every_spec.rb +109 -0
- data/spec/schedule_in_spec.rb +80 -0
- data/spec/schedule_interval_spec.rb +128 -0
- data/spec/scheduler_spec.rb +831 -124
- data/spec/spec_helper.rb +65 -0
- data/spec/threads_spec.rb +75 -0
- metadata +64 -59
- data/README.rdoc +0 -661
- data/lib/rufus/otime.rb +0 -3
- data/lib/rufus/sc/jobqueues.rb +0 -160
- data/lib/rufus/sc/jobs.rb +0 -471
- data/lib/rufus/sc/rtime.rb +0 -363
- data/lib/rufus/sc/scheduler.rb +0 -636
- data/spec/at_in_spec.rb +0 -47
- data/spec/at_spec.rb +0 -125
- data/spec/blocking_spec.rb +0 -64
- data/spec/cron_spec.rb +0 -134
- data/spec/every_spec.rb +0 -304
- data/spec/exception_spec.rb +0 -113
- data/spec/in_spec.rb +0 -150
- data/spec/mutex_spec.rb +0 -159
- data/spec/rtime_spec.rb +0 -137
- data/spec/schedulable_spec.rb +0 -97
- data/spec/spec_base.rb +0 -87
- data/spec/stress_schedule_unschedule_spec.rb +0 -159
- data/spec/timeout_spec.rb +0 -148
- data/test/kjw.rb +0 -113
- data/test/t.rb +0 -20
data/lib/rufus/otime.rb
DELETED
data/lib/rufus/sc/jobqueues.rb
DELETED
@@ -1,160 +0,0 @@
|
|
1
|
-
#--
|
2
|
-
# Copyright (c) 2006-2013, John Mettraux, jmettraux@gmail.com
|
3
|
-
#
|
4
|
-
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
5
|
-
# of this software and associated documentation files (the "Software"), to deal
|
6
|
-
# in the Software without restriction, including without limitation the rights
|
7
|
-
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
8
|
-
# copies of the Software, and to permit persons to whom the Software is
|
9
|
-
# furnished to do so, subject to the following conditions:
|
10
|
-
#
|
11
|
-
# The above copyright notice and this permission notice shall be included in
|
12
|
-
# all copies or substantial portions of the Software.
|
13
|
-
#
|
14
|
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
15
|
-
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
16
|
-
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
17
|
-
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
18
|
-
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
19
|
-
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
20
|
-
# THE SOFTWARE.
|
21
|
-
#
|
22
|
-
# Made in Japan.
|
23
|
-
#++
|
24
|
-
|
25
|
-
|
26
|
-
require 'thread'
|
27
|
-
|
28
|
-
|
29
|
-
module Rufus
|
30
|
-
module Scheduler
|
31
|
-
|
32
|
-
#
|
33
|
-
# Tracking at/in/every jobs.
|
34
|
-
#
|
35
|
-
# In order of trigger time.
|
36
|
-
#
|
37
|
-
class JobQueue
|
38
|
-
|
39
|
-
# Mapping :at|:in|:every to their respective job classes.
|
40
|
-
#
|
41
|
-
JOB_TYPES = {
|
42
|
-
:at => Rufus::Scheduler::AtJob,
|
43
|
-
:in => Rufus::Scheduler::InJob,
|
44
|
-
:every => Rufus::Scheduler::EveryJob
|
45
|
-
}
|
46
|
-
|
47
|
-
def initialize
|
48
|
-
|
49
|
-
@mutex = Mutex.new
|
50
|
-
@jobs = []
|
51
|
-
end
|
52
|
-
|
53
|
-
# Triggers all the jobs that are scheduled for 'now'.
|
54
|
-
#
|
55
|
-
def trigger_matching_jobs
|
56
|
-
|
57
|
-
now = Time.now
|
58
|
-
|
59
|
-
while job = job_to_trigger(now)
|
60
|
-
job.trigger
|
61
|
-
end
|
62
|
-
end
|
63
|
-
|
64
|
-
# Adds this job to the map.
|
65
|
-
#
|
66
|
-
def <<(job)
|
67
|
-
|
68
|
-
@mutex.synchronize do
|
69
|
-
delete(job.job_id)
|
70
|
-
@jobs << job
|
71
|
-
@jobs.sort! { |j0, j1| j0.at <=> j1.at }
|
72
|
-
end
|
73
|
-
end
|
74
|
-
|
75
|
-
# Removes a job (given its id). Returns nil if the job was not found.
|
76
|
-
#
|
77
|
-
def unschedule(job_id)
|
78
|
-
|
79
|
-
@mutex.synchronize { delete(job_id) }
|
80
|
-
end
|
81
|
-
|
82
|
-
# Returns a mapping job_id => job
|
83
|
-
#
|
84
|
-
def to_h
|
85
|
-
|
86
|
-
@jobs.inject({}) { |h, j| h[j.job_id] = j; h }
|
87
|
-
end
|
88
|
-
|
89
|
-
# Returns a list of jobs of the given type (:at|:in|:every)
|
90
|
-
#
|
91
|
-
def select(type)
|
92
|
-
|
93
|
-
type = JOB_TYPES[type]
|
94
|
-
@jobs.select { |j| j.is_a?(type) }
|
95
|
-
end
|
96
|
-
|
97
|
-
def size
|
98
|
-
|
99
|
-
@jobs.size
|
100
|
-
end
|
101
|
-
|
102
|
-
protected
|
103
|
-
|
104
|
-
def delete(job_id)
|
105
|
-
|
106
|
-
if job = @jobs.find { |j| j.job_id == job_id }
|
107
|
-
@jobs.delete(job)
|
108
|
-
end
|
109
|
-
end
|
110
|
-
|
111
|
-
# Returns the next job to trigger. Returns nil if none eligible.
|
112
|
-
#
|
113
|
-
def job_to_trigger(now)
|
114
|
-
|
115
|
-
@mutex.synchronize do
|
116
|
-
if @jobs.size > 0 && now.to_f >= @jobs.first.at
|
117
|
-
@jobs.shift
|
118
|
-
else
|
119
|
-
nil
|
120
|
-
end
|
121
|
-
end
|
122
|
-
end
|
123
|
-
end
|
124
|
-
|
125
|
-
#
|
126
|
-
# Tracking cron jobs.
|
127
|
-
#
|
128
|
-
class CronJobQueue < JobQueue
|
129
|
-
|
130
|
-
def initialize
|
131
|
-
|
132
|
-
super
|
133
|
-
@last_cron_second = nil
|
134
|
-
end
|
135
|
-
|
136
|
-
def trigger_matching_jobs
|
137
|
-
|
138
|
-
now = Time.now
|
139
|
-
|
140
|
-
return if now.sec == @last_cron_second
|
141
|
-
@last_cron_second = now.sec
|
142
|
-
#
|
143
|
-
# ensuring the crons are checked within 1 second (not 1.2 second)
|
144
|
-
|
145
|
-
jobs = @mutex.synchronize { @jobs.dup }
|
146
|
-
|
147
|
-
jobs.each { |job| job.trigger_if_matches(now) }
|
148
|
-
end
|
149
|
-
|
150
|
-
def <<(job)
|
151
|
-
|
152
|
-
@mutex.synchronize do
|
153
|
-
delete(job.job_id)
|
154
|
-
@jobs << job
|
155
|
-
end
|
156
|
-
end
|
157
|
-
end
|
158
|
-
end
|
159
|
-
end
|
160
|
-
|
data/lib/rufus/sc/jobs.rb
DELETED
@@ -1,471 +0,0 @@
|
|
1
|
-
#--
|
2
|
-
# Copyright (c) 2006-2013, John Mettraux, jmettraux@gmail.com
|
3
|
-
#
|
4
|
-
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
5
|
-
# of this software and associated documentation files (the "Software"), to deal
|
6
|
-
# in the Software without restriction, including without limitation the rights
|
7
|
-
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
8
|
-
# copies of the Software, and to permit persons to whom the Software is
|
9
|
-
# furnished to do so, subject to the following conditions:
|
10
|
-
#
|
11
|
-
# The above copyright notice and this permission notice shall be included in
|
12
|
-
# all copies or substantial portions of the Software.
|
13
|
-
#
|
14
|
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
15
|
-
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
16
|
-
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
17
|
-
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
18
|
-
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
19
|
-
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
20
|
-
# THE SOFTWARE.
|
21
|
-
#
|
22
|
-
# Made in Japan.
|
23
|
-
#++
|
24
|
-
|
25
|
-
|
26
|
-
module Rufus
|
27
|
-
module Scheduler
|
28
|
-
|
29
|
-
#
|
30
|
-
# The base class for all types of jobs.
|
31
|
-
#
|
32
|
-
class Job
|
33
|
-
|
34
|
-
# A reference to the scheduler owning this job
|
35
|
-
#
|
36
|
-
attr_accessor :scheduler
|
37
|
-
|
38
|
-
# The initial, raw, scheduling info (at / in / every / cron)
|
39
|
-
#
|
40
|
-
attr_reader :t
|
41
|
-
|
42
|
-
# Returns the thread instance of the last triggered job.
|
43
|
-
# May be null (especially before the first trigger).
|
44
|
-
#
|
45
|
-
attr_reader :last_job_thread
|
46
|
-
|
47
|
-
# The job parameters (passed via the schedule method)
|
48
|
-
#
|
49
|
-
attr_reader :params
|
50
|
-
|
51
|
-
# The block to call when triggering
|
52
|
-
#
|
53
|
-
attr_reader :block
|
54
|
-
|
55
|
-
# Last time the job executed
|
56
|
-
# (for an {At|In}Job, it will mean 'not executed' if nil or when
|
57
|
-
# it got executed if set)
|
58
|
-
#
|
59
|
-
# (
|
60
|
-
# Last time job got triggered (most useful with EveryJob, but can be
|
61
|
-
# useful with remaining instances of At/InJob (are they done ?))
|
62
|
-
# )
|
63
|
-
#
|
64
|
-
attr_reader :last
|
65
|
-
|
66
|
-
# The identifier for this job.
|
67
|
-
#
|
68
|
-
attr_reader :job_id
|
69
|
-
|
70
|
-
# Instantiating the job.
|
71
|
-
#
|
72
|
-
def initialize(scheduler, t, params, &block)
|
73
|
-
|
74
|
-
@scheduler = scheduler
|
75
|
-
@t = t
|
76
|
-
@params = params
|
77
|
-
@block = block || params[:schedulable]
|
78
|
-
|
79
|
-
raise_on_unknown_params
|
80
|
-
|
81
|
-
@running = false
|
82
|
-
@paused = false
|
83
|
-
|
84
|
-
raise ArgumentError.new(
|
85
|
-
'no block or :schedulable passed, nothing to schedule'
|
86
|
-
) unless @block
|
87
|
-
|
88
|
-
@params[:tags] = Array(@params[:tags])
|
89
|
-
|
90
|
-
@job_id = params[:job_id] || "#{self.class.name}_#{self.object_id.to_s}"
|
91
|
-
|
92
|
-
determine_at
|
93
|
-
end
|
94
|
-
|
95
|
-
# Returns true if this job is currently running (in the middle of #trigger)
|
96
|
-
#
|
97
|
-
# Note : paused? is not related to running?
|
98
|
-
#
|
99
|
-
def running
|
100
|
-
|
101
|
-
@running
|
102
|
-
end
|
103
|
-
|
104
|
-
alias running? running
|
105
|
-
|
106
|
-
# Returns true if this job is paused, false else.
|
107
|
-
#
|
108
|
-
# A paused job is still scheduled, but does not trigger.
|
109
|
-
#
|
110
|
-
# Note : paused? is not related to running?
|
111
|
-
#
|
112
|
-
def paused?
|
113
|
-
|
114
|
-
@paused
|
115
|
-
end
|
116
|
-
|
117
|
-
# Pauses this job (sets the paused flag to true).
|
118
|
-
#
|
119
|
-
# Note that it will not pause the execution of a block currently 'running'.
|
120
|
-
# Future triggering of the job will not occur until #resume is called.
|
121
|
-
#
|
122
|
-
# Note too that, during the pause time, the schedule kept the same. Calling
|
123
|
-
# #resume will not force old triggers in.
|
124
|
-
#
|
125
|
-
def pause
|
126
|
-
|
127
|
-
@paused = true
|
128
|
-
end
|
129
|
-
|
130
|
-
# Resumes this job (sets the paused flag to false).
|
131
|
-
#
|
132
|
-
# This job will trigger again.
|
133
|
-
#
|
134
|
-
def resume
|
135
|
-
|
136
|
-
@paused = false
|
137
|
-
end
|
138
|
-
|
139
|
-
# Returns the list of tags attached to the job.
|
140
|
-
#
|
141
|
-
def tags
|
142
|
-
|
143
|
-
@params[:tags]
|
144
|
-
end
|
145
|
-
|
146
|
-
# Sets the list of tags attached to the job (Usually they are set
|
147
|
-
# via the schedule every/at/in/cron method).
|
148
|
-
#
|
149
|
-
def tags=(tags)
|
150
|
-
|
151
|
-
@params[:tags] = Array(tags)
|
152
|
-
end
|
153
|
-
|
154
|
-
# Generally returns the string/float/integer used to schedule the job
|
155
|
-
# (seconds, time string, date string)
|
156
|
-
#
|
157
|
-
def schedule_info
|
158
|
-
|
159
|
-
@t
|
160
|
-
end
|
161
|
-
|
162
|
-
# Triggers the job.
|
163
|
-
#
|
164
|
-
def trigger(t=Time.now)
|
165
|
-
|
166
|
-
return if @paused
|
167
|
-
|
168
|
-
@last = t
|
169
|
-
job_thread = nil
|
170
|
-
to_job = nil
|
171
|
-
|
172
|
-
return if @running and (params[:allow_overlapping] == false)
|
173
|
-
|
174
|
-
@running = true
|
175
|
-
|
176
|
-
@scheduler.send(:trigger_job, @params) do
|
177
|
-
#
|
178
|
-
# Note that #trigger_job is protected, hence the #send
|
179
|
-
# (Only jobs know about this method of the scheduler)
|
180
|
-
|
181
|
-
job_thread = Thread.current
|
182
|
-
|
183
|
-
job_thread[
|
184
|
-
"rufus_scheduler__trigger_thread__#{@scheduler.object_id}"
|
185
|
-
] = self
|
186
|
-
|
187
|
-
@last_job_thread = job_thread
|
188
|
-
|
189
|
-
# note that add_job and add_cron_job ensured that :blocking is
|
190
|
-
# not used along :timeout
|
191
|
-
|
192
|
-
if to = @params[:timeout]
|
193
|
-
|
194
|
-
to_job = @scheduler.in(to, :parent => self, :tags => 'timeout') do
|
195
|
-
|
196
|
-
if job_thread && job_thread.alive?
|
197
|
-
job_thread.raise(Rufus::Scheduler::TimeOutError)
|
198
|
-
end
|
199
|
-
end
|
200
|
-
end
|
201
|
-
|
202
|
-
begin
|
203
|
-
|
204
|
-
trigger_block
|
205
|
-
|
206
|
-
job_thread[
|
207
|
-
"rufus_scheduler__trigger_thread__#{@scheduler.object_id}"
|
208
|
-
] = nil
|
209
|
-
|
210
|
-
job_thread = nil
|
211
|
-
|
212
|
-
to_job.unschedule if to_job
|
213
|
-
|
214
|
-
rescue (@scheduler.options[:exception] || Exception) => e
|
215
|
-
|
216
|
-
@scheduler.do_handle_exception(self, e)
|
217
|
-
end
|
218
|
-
|
219
|
-
@running = false
|
220
|
-
end
|
221
|
-
|
222
|
-
end
|
223
|
-
|
224
|
-
# Simply encapsulating the block#call/trigger operation, for easy
|
225
|
-
# override.
|
226
|
-
#
|
227
|
-
def trigger_block
|
228
|
-
|
229
|
-
@block.respond_to?(:call) ?
|
230
|
-
@block.call(self) : @block.trigger(@params.merge(:job => self))
|
231
|
-
end
|
232
|
-
|
233
|
-
# Unschedules this job.
|
234
|
-
#
|
235
|
-
def unschedule
|
236
|
-
|
237
|
-
@scheduler.unschedule(self.job_id)
|
238
|
-
end
|
239
|
-
|
240
|
-
protected
|
241
|
-
|
242
|
-
def known_params
|
243
|
-
|
244
|
-
[ :allow_overlapping,
|
245
|
-
:blocking,
|
246
|
-
:discard_past,
|
247
|
-
:job_id,
|
248
|
-
:mutex,
|
249
|
-
:schedulable,
|
250
|
-
:tags,
|
251
|
-
:timeout ]
|
252
|
-
end
|
253
|
-
|
254
|
-
def self.known_params(*args)
|
255
|
-
|
256
|
-
define_method :known_params do
|
257
|
-
super() + args
|
258
|
-
end
|
259
|
-
end
|
260
|
-
|
261
|
-
def raise_on_unknown_params
|
262
|
-
|
263
|
-
rem = @params.keys - known_params
|
264
|
-
|
265
|
-
raise(
|
266
|
-
ArgumentError,
|
267
|
-
"unknown option#{rem.size > 1 ? 's' : '' }: " +
|
268
|
-
"#{rem.map(&:inspect).join(', ')}",
|
269
|
-
caller[3..-1]
|
270
|
-
) if rem.any?
|
271
|
-
end
|
272
|
-
end
|
273
|
-
|
274
|
-
#
|
275
|
-
# The base class of at/in/every jobs.
|
276
|
-
#
|
277
|
-
class SimpleJob < Job
|
278
|
-
|
279
|
-
# When the job is supposed to trigger
|
280
|
-
#
|
281
|
-
attr_reader :at
|
282
|
-
|
283
|
-
# Last time it triggered
|
284
|
-
#
|
285
|
-
attr_reader :last
|
286
|
-
|
287
|
-
def determine_at
|
288
|
-
|
289
|
-
@at = Rufus.at_to_f(@t)
|
290
|
-
end
|
291
|
-
|
292
|
-
# Returns the next time (or the unique time) this job is meant to trigger
|
293
|
-
#
|
294
|
-
def next_time
|
295
|
-
|
296
|
-
Time.at(@at)
|
297
|
-
end
|
298
|
-
end
|
299
|
-
|
300
|
-
#
|
301
|
-
# Job that occurs once, in a certain amount of time.
|
302
|
-
#
|
303
|
-
class InJob < SimpleJob
|
304
|
-
|
305
|
-
known_params :parent
|
306
|
-
|
307
|
-
# If this InJob is a timeout job, parent points to the job that
|
308
|
-
# is subject to the timeout.
|
309
|
-
#
|
310
|
-
attr_reader :parent
|
311
|
-
|
312
|
-
def initialize(scheduler, t, params)
|
313
|
-
|
314
|
-
@parent = params[:parent]
|
315
|
-
super
|
316
|
-
end
|
317
|
-
|
318
|
-
protected
|
319
|
-
|
320
|
-
def determine_at
|
321
|
-
|
322
|
-
iin = @t.is_a?(Fixnum) || @t.is_a?(Float) ?
|
323
|
-
@t : Rufus.parse_duration_string(@t)
|
324
|
-
|
325
|
-
@at = (Time.now + iin).to_f
|
326
|
-
end
|
327
|
-
end
|
328
|
-
|
329
|
-
#
|
330
|
-
# Job that occurs once, at a certain point in time.
|
331
|
-
#
|
332
|
-
class AtJob < SimpleJob
|
333
|
-
end
|
334
|
-
|
335
|
-
#
|
336
|
-
# Recurring job with a certain frequency.
|
337
|
-
#
|
338
|
-
class EveryJob < SimpleJob
|
339
|
-
|
340
|
-
known_params :first_in, :first_at
|
341
|
-
|
342
|
-
# The frequency, in seconds, of this EveryJob
|
343
|
-
#
|
344
|
-
attr_reader :frequency
|
345
|
-
|
346
|
-
def initialize(scheduler, t, params, &block)
|
347
|
-
|
348
|
-
super
|
349
|
-
|
350
|
-
determine_frequency
|
351
|
-
determine_at
|
352
|
-
end
|
353
|
-
|
354
|
-
# Triggers the job (and reschedules it).
|
355
|
-
#
|
356
|
-
def trigger
|
357
|
-
|
358
|
-
schedule_next
|
359
|
-
|
360
|
-
super
|
361
|
-
end
|
362
|
-
|
363
|
-
protected
|
364
|
-
|
365
|
-
def determine_frequency
|
366
|
-
|
367
|
-
@frequency =
|
368
|
-
if @t.is_a?(Fixnum) || @t.is_a?(Float)
|
369
|
-
@t
|
370
|
-
else
|
371
|
-
Rufus.parse_duration_string(@t)
|
372
|
-
end
|
373
|
-
|
374
|
-
raise ArgumentError.new(
|
375
|
-
'cannot initialize an EveryJob with a <= 0.0 frequency'
|
376
|
-
) if @frequency <= 0.0
|
377
|
-
end
|
378
|
-
|
379
|
-
def determine_at
|
380
|
-
|
381
|
-
return unless @frequency
|
382
|
-
|
383
|
-
@last = @at
|
384
|
-
# the first time, @last will be nil
|
385
|
-
|
386
|
-
now = Time.now.to_f
|
387
|
-
|
388
|
-
@at = if @last
|
389
|
-
@last + @frequency
|
390
|
-
else
|
391
|
-
if fi = @params[:first_in]
|
392
|
-
now + Rufus.duration_to_f(fi)
|
393
|
-
elsif fa = @params[:first_at]
|
394
|
-
Rufus.at_to_f(fa)
|
395
|
-
else
|
396
|
-
now + @frequency
|
397
|
-
end
|
398
|
-
end
|
399
|
-
|
400
|
-
while @at < now do
|
401
|
-
@at += @frequency
|
402
|
-
end if @params[:discard_past]
|
403
|
-
end
|
404
|
-
|
405
|
-
# It's an every job, have to schedule next time it occurs...
|
406
|
-
#
|
407
|
-
def schedule_next
|
408
|
-
|
409
|
-
determine_at
|
410
|
-
|
411
|
-
@scheduler.send(:add_job, self)
|
412
|
-
end
|
413
|
-
end
|
414
|
-
|
415
|
-
#
|
416
|
-
# Recurring job, cron style.
|
417
|
-
#
|
418
|
-
class CronJob < Job
|
419
|
-
|
420
|
-
# The CronLine instance, it holds all the info about the cron schedule
|
421
|
-
#
|
422
|
-
attr_reader :cron_line
|
423
|
-
|
424
|
-
# The job parameters (passed via the schedule method)
|
425
|
-
#
|
426
|
-
attr_reader :params
|
427
|
-
|
428
|
-
# The block to call when triggering
|
429
|
-
#
|
430
|
-
attr_reader :block
|
431
|
-
|
432
|
-
# Creates a new CronJob instance.
|
433
|
-
#
|
434
|
-
def initialize(scheduler, cron_string, params, &block)
|
435
|
-
|
436
|
-
super
|
437
|
-
|
438
|
-
@cron_line = case @t
|
439
|
-
|
440
|
-
when String then CronLine.new(@t)
|
441
|
-
when CronLine then @t
|
442
|
-
|
443
|
-
else raise ArgumentError.new(
|
444
|
-
"cannot initialize a CronJob out of #{@t.inspect}")
|
445
|
-
end
|
446
|
-
end
|
447
|
-
|
448
|
-
def trigger_if_matches(time)
|
449
|
-
|
450
|
-
return if @paused
|
451
|
-
|
452
|
-
trigger(time) if @cron_line.matches?(time)
|
453
|
-
end
|
454
|
-
|
455
|
-
# Returns the next time this job is meant to trigger
|
456
|
-
#
|
457
|
-
def next_time(from=Time.now)
|
458
|
-
|
459
|
-
@cron_line.next_time(from)
|
460
|
-
end
|
461
|
-
|
462
|
-
protected
|
463
|
-
|
464
|
-
def determine_at
|
465
|
-
|
466
|
-
# empty
|
467
|
-
end
|
468
|
-
end
|
469
|
-
end
|
470
|
-
end
|
471
|
-
|