rufus-scheduler 2.0.6 → 2.0.7

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