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.
@@ -67,16 +67,23 @@ module Scheduler
67
67
  #
68
68
  attr_reader :job_id
69
69
 
70
+ attr_accessor :running
70
71
 
71
72
  # Instantiating the job.
72
73
  #
73
- def initialize (scheduler, t, params, &block)
74
+ def initialize(scheduler, t, params, &block)
74
75
 
75
76
  @scheduler = scheduler
76
77
  @t = t
77
78
  @params = params
78
79
  @block = block || params[:schedulable]
79
80
 
81
+ @running = false
82
+ @allow_overlapping = true
83
+ if !params[:allow_overlapping].nil?
84
+ @allow_overlapping = params[:allow_overlapping]
85
+ end
86
+
80
87
  raise ArgumentError.new(
81
88
  'no block or :schedulable passed, nothing to schedule'
82
89
  ) unless @block
@@ -98,7 +105,7 @@ module Scheduler
98
105
  # Sets the list of tags attached to the job (Usually they are set
99
106
  # via the schedule every/at/in/cron method).
100
107
  #
101
- def tags= (tags)
108
+ def tags=(tags)
102
109
 
103
110
  @params[:tags] = Array(tags)
104
111
  end
@@ -113,18 +120,24 @@ module Scheduler
113
120
 
114
121
  # Triggers the job.
115
122
  #
116
- def trigger (t=Time.now)
123
+ def trigger(t=Time.now)
117
124
 
118
125
  @last = t
119
126
  job_thread = nil
120
127
  to_job = nil
121
128
 
129
+ return if @running && !@allow_overlapping
130
+
131
+ @running = true
122
132
  @scheduler.send(:trigger_job, @params[:blocking]) do
123
133
  #
124
134
  # Note that #trigger_job is protected, hence the #send
125
135
  # (Only jobs know about this method of the scheduler)
126
136
 
127
137
  job_thread = Thread.current
138
+ job_thread[
139
+ "rufus_scheduler__trigger_thread__#{@scheduler.object_id}"
140
+ ] = true
128
141
  @last_job_thread = job_thread
129
142
 
130
143
  begin
@@ -134,6 +147,8 @@ module Scheduler
134
147
  job_thread = nil
135
148
  to_job.unschedule if to_job
136
149
 
150
+ @running = false
151
+
137
152
  rescue Exception => e
138
153
 
139
154
  @scheduler.handle_exception(self, e)
@@ -154,6 +169,7 @@ module Scheduler
154
169
  end
155
170
  end
156
171
  end
172
+
157
173
  end
158
174
 
159
175
  # Simply encapsulating the block#call/trigger operation, for easy
@@ -207,7 +223,7 @@ module Scheduler
207
223
  #
208
224
  attr_reader :parent
209
225
 
210
- def initialize (scheduler, t, params)
226
+ def initialize(scheduler, t, params)
211
227
  @parent = params[:parent]
212
228
  super
213
229
  end
@@ -238,7 +254,7 @@ module Scheduler
238
254
  #
239
255
  attr_reader :frequency
240
256
 
241
- def initialize (scheduler, t, params, &block)
257
+ def initialize(scheduler, t, params, &block)
242
258
  super
243
259
  determine_frequency
244
260
  determine_at
@@ -310,7 +326,7 @@ module Scheduler
310
326
 
311
327
  # Creates a new CronJob instance.
312
328
  #
313
- def initialize (scheduler, cron_string, params, &block)
329
+ def initialize(scheduler, cron_string, params, &block)
314
330
 
315
331
  super
316
332
 
@@ -319,18 +335,19 @@ module Scheduler
319
335
  when String then CronLine.new(@t)
320
336
  when CronLine then @t
321
337
 
322
- else raise "cannot initialize a CronJob out of #{@t.inspect}"
338
+ else raise ArgumentError.new(
339
+ "cannot initialize a CronJob out of #{@t.inspect}")
323
340
  end
324
341
  end
325
342
 
326
- def trigger_if_matches (time)
343
+ def trigger_if_matches(time)
327
344
 
328
345
  trigger(time) if @cron_line.matches?(time)
329
346
  end
330
347
 
331
348
  # Returns the next time this job is meant to trigger
332
349
  #
333
- def next_time (from=Time.now)
350
+ def next_time(from=Time.now)
334
351
 
335
352
  @cron_line.next_time(from)
336
353
  end
@@ -338,10 +355,10 @@ module Scheduler
338
355
  protected
339
356
 
340
357
  def determine_at
358
+
341
359
  # empty
342
360
  end
343
361
  end
344
-
345
362
  end
346
363
  end
347
364
 
@@ -24,21 +24,37 @@
24
24
 
25
25
 
26
26
  require 'date'
27
- #require 'parsedate'
28
27
 
29
28
 
30
29
  module Rufus
31
30
 
31
+ #--
32
+ #
33
+ # keeping that as a note.
34
+ #
35
+ #require 'tzinfo'
36
+ #def time_zone(time)
37
+ # offset = time.utc_offset / 3600
38
+ # offset = offset < 0 ? offset.to_s : "+#{offset}"
39
+ # TZInfo::Timezone.get("Etc/GMT#{offset}")
40
+ #end
41
+ #def timeshift(time, tz)
42
+ # tz = TZInfo::Timezone.get(tz) unless tz.is_a?(TZInfo::Timezone)
43
+ # t = tz.utc_to_local(time.getutc)
44
+ # Time.parse(t.to_s[0..-5])
45
+ #end
46
+ #++
47
+
32
48
  # Returns the current time as an ISO date string
33
49
  #
34
50
  def Rufus.now
35
51
 
36
- to_iso8601_date(Time.new())
52
+ to_iso8601_date(Time.new)
37
53
  end
38
54
 
39
55
  # As the name implies.
40
56
  #
41
- def Rufus.to_iso8601_date (date)
57
+ def Rufus.to_iso8601_date(date)
42
58
 
43
59
  date = case date
44
60
  when Date then date
@@ -55,9 +71,9 @@ module Rufus
55
71
 
56
72
  # the old method we used to generate our ISO datetime strings
57
73
  #
58
- def Rufus.time_to_iso8601_date (time)
74
+ def Rufus.time_to_iso8601_date(time)
59
75
 
60
- s = time.getutc().strftime(TIME_FORMAT)
76
+ s = time.getutc.strftime(TIME_FORMAT)
61
77
  o = time.utc_offset / 3600
62
78
  o = "#{o}00"
63
79
  o = "0#{o}" if o.length < 4
@@ -68,7 +84,7 @@ module Rufus
68
84
 
69
85
  # Returns a Ruby time
70
86
  #
71
- def Rufus.to_ruby_time (sdate)
87
+ def Rufus.to_ruby_time(sdate)
72
88
 
73
89
  DateTime.parse(sdate)
74
90
  end
@@ -99,12 +115,12 @@ module Rufus
99
115
  #
100
116
  # Rufus.parse_time_string "0.5" # => 0.5
101
117
  # Rufus.parse_time_string "500" # => 0.5
102
- # Rufus.parse_time_string "1000" # => 1.0
118
+ # Rufus.parse_time_string "1000" # => 1.0
103
119
  # Rufus.parse_time_string "1h" # => 3600.0
104
- # Rufus.parse_time_string "1h10s" # => 3610.0
105
- # Rufus.parse_time_string "1w2d" # => 777600.0
120
+ # Rufus.parse_time_string "1h10s" # => 3610.0
121
+ # Rufus.parse_time_string "1w2d" # => 777600.0
106
122
  #
107
- def Rufus.parse_time_string (string)
123
+ def Rufus.parse_time_string(string)
108
124
 
109
125
  return string.to_f if FLOAT_DURATION.match(string)
110
126
 
@@ -136,7 +152,7 @@ module Rufus
136
152
 
137
153
  multiplier = DURATIONS[c]
138
154
 
139
- raise "unknown time char '#{c}'" unless multiplier
155
+ raise ArgumentError.new("unknown time char '#{c}'") unless multiplier
140
156
 
141
157
  result = result + (value * multiplier)
142
158
  end
@@ -148,8 +164,9 @@ module Rufus
148
164
  alias_method :parse_duration_string, :parse_time_string
149
165
  end
150
166
 
151
- #
167
+ #--
152
168
  # conversion methods between Date[Time] and Time
169
+ #++
153
170
 
154
171
  #--
155
172
  # Ruby Cookbook 1st edition p.111
@@ -159,21 +176,14 @@ module Rufus
159
176
 
160
177
  # Converts a Time instance to a DateTime one
161
178
  #
162
- def Rufus.to_datetime (time)
179
+ def Rufus.to_datetime(time)
163
180
 
164
181
  s = time.sec + Rational(time.usec, 10**6)
165
182
  o = Rational(time.utc_offset, 3600 * 24)
166
183
 
167
184
  begin
168
185
 
169
- DateTime.new(
170
- time.year,
171
- time.month,
172
- time.day,
173
- time.hour,
174
- time.min,
175
- s,
176
- o)
186
+ DateTime.new(time.year, time.month, time.day, time.hour, time.min, s, o)
177
187
 
178
188
  rescue Exception => e
179
189
 
@@ -188,17 +198,17 @@ module Rufus
188
198
  end
189
199
  end
190
200
 
191
- def Rufus.to_gm_time (dtime)
201
+ def Rufus.to_gm_time(dtime)
192
202
 
193
203
  to_ttime(dtime.new_offset, :gm)
194
204
  end
195
205
 
196
- def Rufus.to_local_time (dtime)
206
+ def Rufus.to_local_time(dtime)
197
207
 
198
208
  to_ttime(dtime.new_offset(DateTime.now.offset-offset), :local)
199
209
  end
200
210
 
201
- def Rufus.to_ttime (d, method)
211
+ def Rufus.to_ttime(d, method)
202
212
 
203
213
  usec = (d.sec_fraction * 3600 * 24 * (10**6)).to_i
204
214
  Time.send(method, d.year, d.month, d.day, d.hour, d.min, d.sec, usec)
@@ -206,10 +216,10 @@ module Rufus
206
216
 
207
217
  # Turns a number of seconds into a a time string
208
218
  #
209
- # Rufus.to_duration_string 0 # => '0s'
210
- # Rufus.to_duration_string 60 # => '1m'
211
- # Rufus.to_duration_string 3661 # => '1h1m1s'
212
- # Rufus.to_duration_string 7 * 24 * 3600 # => '1w'
219
+ # Rufus.to_duration_string 0 # => '0s'
220
+ # Rufus.to_duration_string 60 # => '1m'
221
+ # Rufus.to_duration_string 3661 # => '1h1m1s'
222
+ # Rufus.to_duration_string 7 * 24 * 3600 # => '1w'
213
223
  # Rufus.to_duration_string 30 * 24 * 3600 + 1 # => "4w2d1s"
214
224
  #
215
225
  # It goes from seconds to the year. Months are not counted (as they
@@ -225,8 +235,8 @@ module Rufus
225
235
  # If a Float value is passed, milliseconds will be displayed without
226
236
  # 'marker'
227
237
  #
228
- # Rufus.to_duration_string 0.051 # =>"51"
229
- # Rufus.to_duration_string 7.051 # =>"7s51"
238
+ # Rufus.to_duration_string 0.051 # =>"51"
239
+ # Rufus.to_duration_string 7.051 # =>"7s51"
230
240
  # Rufus.to_duration_string 0.120 + 30 * 24 * 3600 + 1 # =>"4w2d1s120"
231
241
  #
232
242
  # (this behaviour mirrors the one found for parse_time_string()).
@@ -238,18 +248,18 @@ module Rufus
238
248
  # * :drop_seconds, if set to true, seconds and milliseconds will be trimmed
239
249
  # from the result
240
250
  #
241
- def Rufus.to_duration_string (seconds, options={})
251
+ def Rufus.to_duration_string(seconds, options={})
242
252
 
243
253
  return (options[:drop_seconds] ? '0m' : '0s') if seconds <= 0
244
254
 
245
255
  h = to_duration_hash seconds, options
246
256
 
247
- s = DU_KEYS.inject('') do |r, key|
257
+ s = DU_KEYS.inject('') { |r, key|
248
258
  count = h[key]
249
259
  count = nil if count == 0
250
260
  r << "#{count}#{key}" if count
251
261
  r
252
- end
262
+ }
253
263
 
254
264
  ms = h[:ms]
255
265
  s << ms.to_s if ms
@@ -280,7 +290,7 @@ module Rufus
280
290
  # * :drop_seconds, if set to true, seconds and milliseconds will be trimmed
281
291
  # from the result
282
292
  #
283
- def Rufus.to_duration_hash (seconds, options={})
293
+ def Rufus.to_duration_hash(seconds, options={})
284
294
 
285
295
  h = {}
286
296
 
@@ -313,18 +323,17 @@ module Rufus
313
323
  #
314
324
  # will yield 10.0
315
325
  #
316
- def Rufus.duration_to_f (s)
326
+ def Rufus.duration_to_f(s)
317
327
 
318
328
  return s if s.kind_of?(Float)
319
329
  return parse_time_string(s) if s.kind_of?(String)
320
330
  Float(s.to_s)
321
331
  end
322
332
 
323
- #
324
333
  # Ensures an 'at' value is translated to a float
325
334
  # (to be compared with the float coming from time.to_f)
326
335
  #
327
- def Rufus.at_to_f (at)
336
+ def Rufus.at_to_f(at)
328
337
 
329
338
  # TODO : use chronic if present
330
339
 
@@ -360,6 +369,5 @@ module Rufus
360
369
  end
361
370
 
362
371
  DU_KEYS = DURATIONS2M.collect { |k, v| k.to_sym }
363
-
364
372
  end
365
373
 
@@ -40,10 +40,10 @@ module Rufus::Scheduler
40
40
  # object quack (respond to :trigger anyway).
41
41
  #
42
42
  module Schedulable
43
- def call (job)
43
+ def call(job)
44
44
  trigger(job.params)
45
45
  end
46
- def trigger (params)
46
+ def trigger(params)
47
47
  raise NotImplementedError.new('implementation is missing')
48
48
  end
49
49
  end
@@ -61,7 +61,7 @@ module Rufus::Scheduler
61
61
  #
62
62
  module LegacyMethods
63
63
 
64
- def find_jobs (tag=nil)
64
+ def find_jobs(tag=nil)
65
65
  tag ? find_by_tag(tag) : all_jobs.values
66
66
  end
67
67
  def at_job_count
@@ -97,7 +97,7 @@ module Rufus::Scheduler
97
97
 
98
98
  # Instantiates a Rufus::Scheduler.
99
99
  #
100
- def initialize (opts={})
100
+ def initialize(opts={})
101
101
 
102
102
  @options = opts
103
103
 
@@ -109,7 +109,7 @@ module Rufus::Scheduler
109
109
 
110
110
  # Instantiates and starts a new Rufus::Scheduler.
111
111
  #
112
- def self.start_new (opts={})
112
+ def self.start_new(opts={})
113
113
 
114
114
  s = self.new(opts)
115
115
  s.start
@@ -128,7 +128,7 @@ module Rufus::Scheduler
128
128
  #
129
129
  # will order an espresso (well sort of) in 20 minutes.
130
130
  #
131
- def in (t, s=nil, opts={}, &block)
131
+ def in(t, s=nil, opts={}, &block)
132
132
 
133
133
  add_job(InJob.new(self, t, combine_opts(s, opts), &block))
134
134
  end
@@ -142,7 +142,7 @@ module Rufus::Scheduler
142
142
  #
143
143
  # pizza is for Thursday at 2000 (if the shop brochure is right).
144
144
  #
145
- def at (t, s=nil, opts={}, &block)
145
+ def at(t, s=nil, opts={}, &block)
146
146
 
147
147
  add_job(AtJob.new(self, t, combine_opts(s, opts), &block))
148
148
  end
@@ -156,7 +156,7 @@ module Rufus::Scheduler
156
156
  #
157
157
  # checking blood pressure every 5 months and 1 week.
158
158
  #
159
- def every (t, s=nil, opts={}, &block)
159
+ def every(t, s=nil, opts={}, &block)
160
160
 
161
161
  add_job(EveryJob.new(self, t, combine_opts(s, opts), &block))
162
162
  end
@@ -169,7 +169,7 @@ module Rufus::Scheduler
169
169
  # puts 'activate security system'
170
170
  # end
171
171
  #
172
- def cron (cronstring, s=nil, opts={}, &block)
172
+ def cron(cronstring, s=nil, opts={}, &block)
173
173
 
174
174
  add_cron_job(CronJob.new(self, cronstring, combine_opts(s, opts), &block))
175
175
  end
@@ -179,7 +179,7 @@ module Rufus::Scheduler
179
179
  #
180
180
  # Returns the job that got unscheduled.
181
181
  #
182
- def unschedule (job_id)
182
+ def unschedule(job_id)
183
183
 
184
184
  @jobs.unschedule(job_id) || @cron_jobs.unschedule(job_id)
185
185
  end
@@ -191,7 +191,7 @@ module Rufus::Scheduler
191
191
  # Feel free to override this method. The default implementation simply
192
192
  # outputs the error message to STDOUT
193
193
  #
194
- def handle_exception (job, exception)
194
+ def handle_exception(job, exception)
195
195
 
196
196
  if self.respond_to?(:log_exception)
197
197
  #
@@ -236,18 +236,28 @@ module Rufus::Scheduler
236
236
 
237
237
  # Returns a list of jobs with the given tag
238
238
  #
239
- def find_by_tag (tag)
239
+ def find_by_tag(tag)
240
240
 
241
241
  all_jobs.values.select { |j| j.tags.include?(tag) }
242
242
  end
243
243
 
244
+ # Returns the current list of trigger threads (threads) dedicated to
245
+ # the execution of jobs.
246
+ #
247
+ def trigger_threads
248
+
249
+ Thread.list.select { |t|
250
+ t["rufus_scheduler__trigger_thread__#{self.object_id}"] == true
251
+ }
252
+ end
253
+
244
254
  protected
245
255
 
246
256
  # Returns a job queue instance.
247
257
  #
248
258
  # (made it into a method for easy override)
249
259
  #
250
- def get_queue (type, opts)
260
+ def get_queue(type, opts)
251
261
 
252
262
  q = if type == :cron
253
263
  opts[:cron_job_queue] || Rufus::Scheduler::CronJobQueue.new
@@ -260,7 +270,7 @@ module Rufus::Scheduler
260
270
  q
261
271
  end
262
272
 
263
- def combine_opts (schedulable, opts)
273
+ def combine_opts(schedulable, opts)
264
274
 
265
275
  if schedulable.respond_to?(:trigger) || schedulable.respond_to?(:call)
266
276
 
@@ -283,7 +293,7 @@ module Rufus::Scheduler
283
293
  @jobs.trigger_matching_jobs
284
294
  end
285
295
 
286
- def add_job (job)
296
+ def add_job(job)
287
297
 
288
298
  complain_if_blocking_and_timeout(job)
289
299
 
@@ -294,7 +304,7 @@ module Rufus::Scheduler
294
304
  job
295
305
  end
296
306
 
297
- def add_cron_job (job)
307
+ def add_cron_job(job)
298
308
 
299
309
  complain_if_blocking_and_timeout(job)
300
310
 
@@ -305,7 +315,7 @@ module Rufus::Scheduler
305
315
 
306
316
  # Raises an error if the job has the params :blocking and :timeout set
307
317
  #
308
- def complain_if_blocking_and_timeout (job)
318
+ def complain_if_blocking_and_timeout(job)
309
319
 
310
320
  raise(
311
321
  ArgumentError.new('cannot set a :timeout on a :blocking job')
@@ -319,7 +329,7 @@ module Rufus::Scheduler
319
329
  # TODO : clarify, the blocking here blocks the whole scheduler, while
320
330
  # EmScheduler blocking triggers for the next tick. Not the same thing ...
321
331
  #
322
- def trigger_job (blocking, &block)
332
+ def trigger_job(blocking, &block)
323
333
 
324
334
  if blocking
325
335
  block.call
@@ -353,7 +363,7 @@ module Rufus::Scheduler
353
363
  "#{self.class} - #{Rufus::Scheduler::VERSION}"
354
364
  end
355
365
 
356
- def stop (opts={})
366
+ def stop(opts={})
357
367
 
358
368
  @thread.exit
359
369
  end
@@ -376,7 +386,7 @@ module Rufus::Scheduler
376
386
  #
377
387
  class SignalScheduler < SchedulerCore
378
388
 
379
- def initialize (opts={})
389
+ def initialize(opts={})
380
390
 
381
391
  super(opts)
382
392
 
@@ -397,7 +407,7 @@ module Rufus::Scheduler
397
407
  #
398
408
  class EmScheduler < SchedulerCore
399
409
 
400
- def initialize (opts={})
410
+ def initialize(opts={})
401
411
 
402
412
  raise LoadError.new(
403
413
  'EventMachine missing, "require \'eventmachine\'" might help'
@@ -431,7 +441,7 @@ module Rufus::Scheduler
431
441
  # If the :stop_em option is passed and set to true, it will stop the
432
442
  # EventMachine (but only if it started the EM by itself !).
433
443
  #
434
- def stop (opts={})
444
+ def stop(opts={})
435
445
 
436
446
  @timer.cancel
437
447
 
@@ -451,7 +461,7 @@ module Rufus::Scheduler
451
461
  # If 'blocking' is set to true, the block will get called at the
452
462
  # 'next_tick'. Else the block will get called via 'defer' (own thread).
453
463
  #
454
- def trigger_job (blocking, &block)
464
+ def trigger_job(blocking, &block)
455
465
 
456
466
  m = blocking ? :next_tick : :defer
457
467
  #