rufus-scheduler 3.0.0 → 3.0.9
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.
- data/CHANGELOG.txt +63 -0
- data/CREDITS.txt +16 -0
- data/LICENSE.txt +1 -1
- data/README.md +389 -7
- data/Rakefile +0 -1
- data/TODO.txt +4 -0
- data/lib/rufus/scheduler/cronline.rb +109 -28
- data/lib/rufus/scheduler/job_array.rb +8 -1
- data/lib/rufus/scheduler/jobs.rb +127 -43
- data/lib/rufus/scheduler/locks.rb +95 -0
- data/lib/rufus/scheduler/util.rb +39 -28
- data/lib/rufus/scheduler.rb +150 -46
- data/rufus-scheduler.gemspec +2 -1
- data/spec/basics_spec.rb +54 -0
- data/spec/cronline_spec.rb +349 -92
- data/spec/error_spec.rb +30 -7
- data/spec/job_array_spec.rb +2 -2
- data/spec/job_at_spec.rb +4 -4
- data/spec/job_cron_spec.rb +42 -3
- data/spec/job_every_spec.rb +24 -5
- data/spec/job_interval_spec.rb +5 -5
- data/spec/job_repeat_spec.rb +86 -38
- data/spec/job_spec.rb +172 -55
- data/spec/lock_custom_spec.rb +47 -0
- data/spec/lock_flock_spec.rb +47 -0
- data/spec/{lockfile_spec.rb → lock_lockfile_spec.rb} +5 -5
- data/spec/lock_spec.rb +59 -0
- data/spec/parse_spec.rb +138 -76
- data/spec/schedule_at_spec.rb +46 -17
- data/spec/schedule_cron_spec.rb +6 -6
- data/spec/schedule_every_spec.rb +12 -12
- data/spec/schedule_in_spec.rb +8 -8
- data/spec/schedule_interval_spec.rb +13 -13
- data/spec/scheduler_spec.rb +213 -119
- data/spec/spec_helper.rb +62 -1
- data/spec/threads_spec.rb +24 -3
- metadata +58 -37
data/lib/rufus/scheduler/util.rb
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#--
|
|
2
|
-
# Copyright (c) 2006-
|
|
2
|
+
# Copyright (c) 2006-2014, John Mettraux, jmettraux@gmail.com
|
|
3
3
|
#
|
|
4
4
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
5
5
|
# of this software and associated documentation files (the "Software"), to deal
|
|
@@ -31,9 +31,9 @@ module Rufus
|
|
|
31
31
|
# time and string methods
|
|
32
32
|
#++
|
|
33
33
|
|
|
34
|
-
def self.parse(o)
|
|
34
|
+
def self.parse(o, opts={})
|
|
35
35
|
|
|
36
|
-
opts
|
|
36
|
+
opts[:no_error] = true
|
|
37
37
|
|
|
38
38
|
parse_cron(o, opts) ||
|
|
39
39
|
parse_in(o, opts) || # covers 'every' schedule strings
|
|
@@ -46,12 +46,15 @@ module Rufus
|
|
|
46
46
|
o.is_a?(String) ? parse_duration(o, opts) : o
|
|
47
47
|
end
|
|
48
48
|
|
|
49
|
-
TZ_REGEX = /\b((?:[a-zA-Z][a-zA-z0-9\-+]+)(?:\/[a-zA-Z0-
|
|
49
|
+
TZ_REGEX = /\b((?:[a-zA-Z][a-zA-z0-9\-+]+)(?:\/[a-zA-Z0-9_\-+]+)?)\b/
|
|
50
50
|
|
|
51
51
|
def self.parse_at(o, opts={})
|
|
52
52
|
|
|
53
53
|
return o if o.is_a?(Time)
|
|
54
54
|
|
|
55
|
+
# TODO: deal with tz if suffixed to Chronic string?
|
|
56
|
+
return Chronic.parse(o, opts) if defined?(Chronic)
|
|
57
|
+
|
|
55
58
|
tz = nil
|
|
56
59
|
s =
|
|
57
60
|
o.to_s.gsub(TZ_REGEX) { |m|
|
|
@@ -68,9 +71,7 @@ module Rufus
|
|
|
68
71
|
|
|
69
72
|
t = Time.parse(s)
|
|
70
73
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
t
|
|
74
|
+
tz ? tz.local_to_utc(t) : t
|
|
74
75
|
|
|
75
76
|
rescue StandardError => se
|
|
76
77
|
|
|
@@ -133,17 +134,17 @@ module Rufus
|
|
|
133
134
|
#
|
|
134
135
|
# Some examples:
|
|
135
136
|
#
|
|
136
|
-
# Rufus::Scheduler.
|
|
137
|
-
# Rufus::Scheduler.
|
|
138
|
-
# Rufus::Scheduler.
|
|
139
|
-
# Rufus::Scheduler.
|
|
140
|
-
# Rufus::Scheduler.
|
|
141
|
-
# Rufus::Scheduler.
|
|
137
|
+
# Rufus::Scheduler.parse_duration "0.5" # => 0.5
|
|
138
|
+
# Rufus::Scheduler.parse_duration "500" # => 0.5
|
|
139
|
+
# Rufus::Scheduler.parse_duration "1000" # => 1.0
|
|
140
|
+
# Rufus::Scheduler.parse_duration "1h" # => 3600.0
|
|
141
|
+
# Rufus::Scheduler.parse_duration "1h10s" # => 3610.0
|
|
142
|
+
# Rufus::Scheduler.parse_duration "1w2d" # => 777600.0
|
|
142
143
|
#
|
|
143
144
|
# Negative time strings are OK (Thanks Danny Fullerton):
|
|
144
145
|
#
|
|
145
|
-
# Rufus::Scheduler.
|
|
146
|
-
# Rufus::Scheduler.
|
|
146
|
+
# Rufus::Scheduler.parse_duration "-0.5" # => -0.5
|
|
147
|
+
# Rufus::Scheduler.parse_duration "-1h" # => -3600.0
|
|
147
148
|
#
|
|
148
149
|
def self.parse_duration(string, opts={})
|
|
149
150
|
|
|
@@ -183,13 +184,22 @@ module Rufus
|
|
|
183
184
|
mod * val
|
|
184
185
|
end
|
|
185
186
|
|
|
187
|
+
class << self
|
|
188
|
+
#-
|
|
189
|
+
# for compatibility with rufus-scheduler 2.x
|
|
190
|
+
#+
|
|
191
|
+
alias parse_duration_string parse_duration
|
|
192
|
+
alias parse_time_string parse_duration
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
|
|
186
196
|
# Turns a number of seconds into a a time string
|
|
187
197
|
#
|
|
188
|
-
# Rufus.
|
|
189
|
-
# Rufus.
|
|
190
|
-
# Rufus.
|
|
191
|
-
# Rufus.
|
|
192
|
-
# Rufus.
|
|
198
|
+
# Rufus.to_duration 0 # => '0s'
|
|
199
|
+
# Rufus.to_duration 60 # => '1m'
|
|
200
|
+
# Rufus.to_duration 3661 # => '1h1m1s'
|
|
201
|
+
# Rufus.to_duration 7 * 24 * 3600 # => '1w'
|
|
202
|
+
# Rufus.to_duration 30 * 24 * 3600 + 1 # => "4w2d1s"
|
|
193
203
|
#
|
|
194
204
|
# It goes from seconds to the year. Months are not counted (as they
|
|
195
205
|
# are of variable length). Weeks are counted.
|
|
@@ -197,16 +207,14 @@ module Rufus
|
|
|
197
207
|
# For 30 days months to be counted, the second parameter of this
|
|
198
208
|
# method can be set to true.
|
|
199
209
|
#
|
|
200
|
-
# Rufus.
|
|
201
|
-
#
|
|
202
|
-
# (to_time_string is an alias for to_duration_string)
|
|
210
|
+
# Rufus.to_duration 30 * 24 * 3600 + 1, true # => "1M1s"
|
|
203
211
|
#
|
|
204
212
|
# If a Float value is passed, milliseconds will be displayed without
|
|
205
213
|
# 'marker'
|
|
206
214
|
#
|
|
207
|
-
# Rufus.
|
|
208
|
-
# Rufus.
|
|
209
|
-
# Rufus.
|
|
215
|
+
# Rufus.to_duration 0.051 # => "51"
|
|
216
|
+
# Rufus.to_duration 7.051 # => "7s51"
|
|
217
|
+
# Rufus.to_duration 0.120 + 30 * 24 * 3600 + 1 # => "4w2d1s120"
|
|
210
218
|
#
|
|
211
219
|
# (this behaviour mirrors the one found for parse_time_string()).
|
|
212
220
|
#
|
|
@@ -238,7 +246,11 @@ module Rufus
|
|
|
238
246
|
end
|
|
239
247
|
|
|
240
248
|
class << self
|
|
249
|
+
#-
|
|
250
|
+
# for compatibility with rufus-scheduler 2.x
|
|
251
|
+
#+
|
|
241
252
|
alias to_duration_string to_duration
|
|
253
|
+
alias to_time_string to_duration
|
|
242
254
|
end
|
|
243
255
|
|
|
244
256
|
# Turns a number of seconds (integer or Float) into a hash like in :
|
|
@@ -250,8 +262,7 @@ module Rufus
|
|
|
250
262
|
# Rufus.to_duration_hash 0.120 + 30 * 24 * 3600 + 1
|
|
251
263
|
# # => { :w => 4, :d => 2, :s => 1, :ms => "120" }
|
|
252
264
|
#
|
|
253
|
-
# This method is used by
|
|
254
|
-
# the scene.
|
|
265
|
+
# This method is used by to_duration behind the scenes.
|
|
255
266
|
#
|
|
256
267
|
# Options are :
|
|
257
268
|
#
|
data/lib/rufus/scheduler.rb
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#--
|
|
2
|
-
# Copyright (c) 2006-
|
|
2
|
+
# Copyright (c) 2006-2014, John Mettraux, jmettraux@gmail.com
|
|
3
3
|
#
|
|
4
4
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
5
5
|
# of this software and associated documentation files (the "Software"), to deal
|
|
@@ -26,7 +26,6 @@ require 'date' if RUBY_VERSION < '1.9.0'
|
|
|
26
26
|
require 'time'
|
|
27
27
|
require 'thread'
|
|
28
28
|
require 'tzinfo'
|
|
29
|
-
require 'fileutils'
|
|
30
29
|
|
|
31
30
|
|
|
32
31
|
module Rufus
|
|
@@ -37,16 +36,28 @@ module Rufus
|
|
|
37
36
|
require 'rufus/scheduler/jobs'
|
|
38
37
|
require 'rufus/scheduler/cronline'
|
|
39
38
|
require 'rufus/scheduler/job_array'
|
|
39
|
+
require 'rufus/scheduler/locks'
|
|
40
40
|
|
|
41
|
-
VERSION = '3.0.
|
|
41
|
+
VERSION = '3.0.9'
|
|
42
|
+
|
|
43
|
+
#
|
|
44
|
+
# A common error class for rufus-scheduler
|
|
45
|
+
#
|
|
46
|
+
class Error < StandardError; end
|
|
42
47
|
|
|
43
48
|
#
|
|
44
49
|
# This error is thrown when the :timeout attribute triggers
|
|
45
50
|
#
|
|
46
|
-
class TimeoutError <
|
|
51
|
+
class TimeoutError < Error; end
|
|
52
|
+
|
|
53
|
+
#
|
|
54
|
+
# For when the scheduler is not running
|
|
55
|
+
# (it got shut down or didn't start because of a lock)
|
|
56
|
+
#
|
|
57
|
+
class NotRunningError < Error; end
|
|
47
58
|
|
|
48
|
-
#MIN_WORK_THREADS =
|
|
49
|
-
MAX_WORK_THREADS =
|
|
59
|
+
#MIN_WORK_THREADS = 3
|
|
60
|
+
MAX_WORK_THREADS = 28
|
|
50
61
|
|
|
51
62
|
attr_accessor :frequency
|
|
52
63
|
attr_reader :started_at
|
|
@@ -82,7 +93,17 @@ module Rufus
|
|
|
82
93
|
|
|
83
94
|
@thread_key = "rufus_scheduler_#{self.object_id}"
|
|
84
95
|
|
|
85
|
-
|
|
96
|
+
@scheduler_lock =
|
|
97
|
+
if lockfile = opts[:lockfile]
|
|
98
|
+
Rufus::Scheduler::FileLock.new(lockfile)
|
|
99
|
+
else
|
|
100
|
+
opts[:scheduler_lock] || Rufus::Scheduler::NullLock.new
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
@trigger_lock = opts[:trigger_lock] || Rufus::Scheduler::NullLock.new
|
|
104
|
+
|
|
105
|
+
# If we can't grab the @scheduler_lock, don't run.
|
|
106
|
+
@scheduler_lock.lock || return
|
|
86
107
|
|
|
87
108
|
start
|
|
88
109
|
end
|
|
@@ -113,7 +134,9 @@ module Rufus
|
|
|
113
134
|
|
|
114
135
|
@started_at = nil
|
|
115
136
|
|
|
116
|
-
jobs.each { |j| j.unschedule }
|
|
137
|
+
#jobs.each { |j| j.unschedule }
|
|
138
|
+
# provokes https://github.com/jmettraux/rufus-scheduler/issue/98
|
|
139
|
+
@jobs.array.each { |j| j.unschedule }
|
|
117
140
|
|
|
118
141
|
@work_queue.clear
|
|
119
142
|
|
|
@@ -123,7 +146,7 @@ module Rufus
|
|
|
123
146
|
kill_all_work_threads
|
|
124
147
|
end
|
|
125
148
|
|
|
126
|
-
|
|
149
|
+
unlock
|
|
127
150
|
end
|
|
128
151
|
|
|
129
152
|
alias stop shutdown
|
|
@@ -140,9 +163,23 @@ module Rufus
|
|
|
140
163
|
|
|
141
164
|
def join
|
|
142
165
|
|
|
166
|
+
fail NotRunningError.new(
|
|
167
|
+
'cannot join scheduler that is not running'
|
|
168
|
+
) unless @thread
|
|
169
|
+
|
|
143
170
|
@thread.join
|
|
144
171
|
end
|
|
145
172
|
|
|
173
|
+
def down?
|
|
174
|
+
|
|
175
|
+
! @started_at
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
def up?
|
|
179
|
+
|
|
180
|
+
!! @started_at
|
|
181
|
+
end
|
|
182
|
+
|
|
146
183
|
def paused?
|
|
147
184
|
|
|
148
185
|
@paused
|
|
@@ -214,9 +251,9 @@ module Rufus
|
|
|
214
251
|
|
|
215
252
|
def schedule(arg, callable=nil, opts={}, &block)
|
|
216
253
|
|
|
217
|
-
|
|
254
|
+
opts[:_t] = Scheduler.parse(arg, opts)
|
|
218
255
|
|
|
219
|
-
case
|
|
256
|
+
case opts[:_t]
|
|
220
257
|
when CronLine then schedule_cron(arg, callable, opts, &block)
|
|
221
258
|
when Time then schedule_at(arg, callable, opts, &block)
|
|
222
259
|
else schedule_in(arg, callable, opts, &block)
|
|
@@ -225,9 +262,9 @@ module Rufus
|
|
|
225
262
|
|
|
226
263
|
def repeat(arg, callable=nil, opts={}, &block)
|
|
227
264
|
|
|
228
|
-
|
|
265
|
+
opts[:_t] = Scheduler.parse(arg, opts)
|
|
229
266
|
|
|
230
|
-
case
|
|
267
|
+
case opts[:_t]
|
|
231
268
|
when CronLine then schedule_cron(arg, callable, opts, &block)
|
|
232
269
|
else schedule_every(arg, callable, opts, &block)
|
|
233
270
|
end
|
|
@@ -297,6 +334,49 @@ module Rufus
|
|
|
297
334
|
@jobs[job_id]
|
|
298
335
|
end
|
|
299
336
|
|
|
337
|
+
# Returns true if the scheduler has acquired the [exclusive] lock and
|
|
338
|
+
# thus may run.
|
|
339
|
+
#
|
|
340
|
+
# Most of the time, a scheduler is run alone and this method should
|
|
341
|
+
# return true. It is useful in cases where among a group of applications
|
|
342
|
+
# only one of them should run the scheduler. For schedulers that should
|
|
343
|
+
# not run, the method should return false.
|
|
344
|
+
#
|
|
345
|
+
# Out of the box, rufus-scheduler proposes the
|
|
346
|
+
# :lockfile => 'path/to/lock/file' scheduler start option. It makes
|
|
347
|
+
# it easy for schedulers on the same machine to determine which should
|
|
348
|
+
# run (the first to write the lockfile and lock it). It uses "man 2 flock"
|
|
349
|
+
# so it probably won't work reliably on distributed file systems.
|
|
350
|
+
#
|
|
351
|
+
# If one needs to use a special/different locking mechanism, the scheduler
|
|
352
|
+
# accepts :scheduler_lock => lock_object. lock_object only needs to respond
|
|
353
|
+
# to #lock
|
|
354
|
+
# and #unlock, and both of these methods should be idempotent.
|
|
355
|
+
#
|
|
356
|
+
# Look at rufus/scheduler/locks.rb for an example.
|
|
357
|
+
#
|
|
358
|
+
def lock
|
|
359
|
+
|
|
360
|
+
@scheduler_lock.lock
|
|
361
|
+
end
|
|
362
|
+
|
|
363
|
+
# Sister method to #lock, is called when the scheduler shuts down.
|
|
364
|
+
#
|
|
365
|
+
def unlock
|
|
366
|
+
|
|
367
|
+
@trigger_lock.unlock
|
|
368
|
+
@scheduler_lock.unlock
|
|
369
|
+
end
|
|
370
|
+
|
|
371
|
+
# Callback called when a job is triggered. If the lock cannot be acquired,
|
|
372
|
+
# the job won't run (though it'll still be scheduled to run again if
|
|
373
|
+
# necessary).
|
|
374
|
+
#
|
|
375
|
+
def confirm_lock
|
|
376
|
+
|
|
377
|
+
@trigger_lock.lock
|
|
378
|
+
end
|
|
379
|
+
|
|
300
380
|
# Returns true if this job is currently scheduled.
|
|
301
381
|
#
|
|
302
382
|
# Takes extra care to answer true if the job is a repeat job
|
|
@@ -348,13 +428,39 @@ module Rufus
|
|
|
348
428
|
jobs(opts.merge(:running => true))
|
|
349
429
|
end
|
|
350
430
|
|
|
431
|
+
def occurrences(time0, time1, format=:per_job)
|
|
432
|
+
|
|
433
|
+
h = {}
|
|
434
|
+
|
|
435
|
+
jobs.each do |j|
|
|
436
|
+
os = j.occurrences(time0, time1)
|
|
437
|
+
h[j] = os if os.any?
|
|
438
|
+
end
|
|
439
|
+
|
|
440
|
+
if format == :timeline
|
|
441
|
+
a = []
|
|
442
|
+
h.each { |j, ts| ts.each { |t| a << [ t, j ] } }
|
|
443
|
+
a.sort_by { |(t, j)| t }
|
|
444
|
+
else
|
|
445
|
+
h
|
|
446
|
+
end
|
|
447
|
+
end
|
|
448
|
+
|
|
449
|
+
def timeline(time0, time1)
|
|
450
|
+
|
|
451
|
+
occurrences(time0, time1, :timeline)
|
|
452
|
+
end
|
|
453
|
+
|
|
351
454
|
def on_error(job, err)
|
|
352
455
|
|
|
353
456
|
pre = err.object_id.to_s
|
|
354
457
|
|
|
458
|
+
ms = {}; mutexes.each { |k, v| ms[k] = v.locked? }
|
|
459
|
+
|
|
355
460
|
stderr.puts("{ #{pre} rufus-scheduler intercepted an error:")
|
|
356
461
|
stderr.puts(" #{pre} job:")
|
|
357
462
|
stderr.puts(" #{pre} #{job.class} #{job.original.inspect} #{job.opts.inspect}")
|
|
463
|
+
# TODO: eventually use a Job#detail or something like that
|
|
358
464
|
stderr.puts(" #{pre} error:")
|
|
359
465
|
stderr.puts(" #{pre} #{err.object_id}")
|
|
360
466
|
stderr.puts(" #{pre} #{err.class}")
|
|
@@ -362,6 +468,34 @@ module Rufus
|
|
|
362
468
|
err.backtrace.each do |l|
|
|
363
469
|
stderr.puts(" #{pre} #{l}")
|
|
364
470
|
end
|
|
471
|
+
stderr.puts(" #{pre} tz:")
|
|
472
|
+
stderr.puts(" #{pre} ENV['TZ']: #{ENV['TZ']}")
|
|
473
|
+
stderr.puts(" #{pre} Time.now: #{Time.now}")
|
|
474
|
+
stderr.puts(" #{pre} scheduler:")
|
|
475
|
+
stderr.puts(" #{pre} object_id: #{object_id}")
|
|
476
|
+
stderr.puts(" #{pre} opts:")
|
|
477
|
+
stderr.puts(" #{pre} #{@opts.inspect}")
|
|
478
|
+
stderr.puts(" #{pre} frequency: #{self.frequency}")
|
|
479
|
+
stderr.puts(" #{pre} scheduler_lock: #{@scheduler_lock.inspect}")
|
|
480
|
+
stderr.puts(" #{pre} trigger_lock: #{@trigger_lock.inspect}")
|
|
481
|
+
stderr.puts(" #{pre} uptime: #{uptime} (#{uptime_s})")
|
|
482
|
+
stderr.puts(" #{pre} down?: #{down?}")
|
|
483
|
+
stderr.puts(" #{pre} threads: #{self.threads.size}")
|
|
484
|
+
stderr.puts(" #{pre} thread: #{self.thread}")
|
|
485
|
+
stderr.puts(" #{pre} thread_key: #{self.thread_key}")
|
|
486
|
+
stderr.puts(" #{pre} work_threads: #{work_threads.size}")
|
|
487
|
+
stderr.puts(" #{pre} active: #{work_threads(:active).size}")
|
|
488
|
+
stderr.puts(" #{pre} vacant: #{work_threads(:vacant).size}")
|
|
489
|
+
stderr.puts(" #{pre} max_work_threads: #{max_work_threads}")
|
|
490
|
+
stderr.puts(" #{pre} mutexes: #{ms.inspect}")
|
|
491
|
+
stderr.puts(" #{pre} jobs: #{jobs.size}")
|
|
492
|
+
stderr.puts(" #{pre} at_jobs: #{at_jobs.size}")
|
|
493
|
+
stderr.puts(" #{pre} in_jobs: #{in_jobs.size}")
|
|
494
|
+
stderr.puts(" #{pre} every_jobs: #{every_jobs.size}")
|
|
495
|
+
stderr.puts(" #{pre} interval_jobs: #{interval_jobs.size}")
|
|
496
|
+
stderr.puts(" #{pre} cron_jobs: #{cron_jobs.size}")
|
|
497
|
+
stderr.puts(" #{pre} running_jobs: #{running_jobs.size}")
|
|
498
|
+
stderr.puts(" #{pre} work_queue: #{work_queue.size}")
|
|
365
499
|
stderr.puts("} #{pre} .")
|
|
366
500
|
|
|
367
501
|
rescue => e
|
|
@@ -388,36 +522,6 @@ module Rufus
|
|
|
388
522
|
end
|
|
389
523
|
end
|
|
390
524
|
|
|
391
|
-
def consider_lockfile
|
|
392
|
-
|
|
393
|
-
@lockfile = nil
|
|
394
|
-
|
|
395
|
-
return true unless f = @opts[:lockfile]
|
|
396
|
-
|
|
397
|
-
raise ArgumentError.new(
|
|
398
|
-
":lockfile argument must be a string, not a #{f.class}"
|
|
399
|
-
) unless f.is_a?(String)
|
|
400
|
-
|
|
401
|
-
FileUtils.mkdir_p(File.dirname(f))
|
|
402
|
-
|
|
403
|
-
f = File.new(f, File::RDWR | File::CREAT)
|
|
404
|
-
locked = f.flock(File::LOCK_NB | File::LOCK_EX)
|
|
405
|
-
|
|
406
|
-
return false unless locked
|
|
407
|
-
|
|
408
|
-
now = Time.now
|
|
409
|
-
|
|
410
|
-
f.print("pid: #{$$}, ")
|
|
411
|
-
f.print("scheduler.object_id: #{self.object_id}, ")
|
|
412
|
-
f.print("time: #{now}, ")
|
|
413
|
-
f.print("timestamp: #{now.to_f}")
|
|
414
|
-
f.flush
|
|
415
|
-
|
|
416
|
-
@lockfile = f
|
|
417
|
-
|
|
418
|
-
true
|
|
419
|
-
end
|
|
420
|
-
|
|
421
525
|
def terminate_all_jobs
|
|
422
526
|
|
|
423
527
|
jobs.each { |j| j.unschedule }
|
|
@@ -502,7 +606,7 @@ module Rufus
|
|
|
502
606
|
|
|
503
607
|
def do_schedule(job_type, t, callable, opts, return_job_instance, block)
|
|
504
608
|
|
|
505
|
-
|
|
609
|
+
fail NotRunningError.new(
|
|
506
610
|
'cannot schedule, scheduler is down or shutting down'
|
|
507
611
|
) if @started_at == nil
|
|
508
612
|
|
|
@@ -512,8 +616,8 @@ module Rufus
|
|
|
512
616
|
job_class =
|
|
513
617
|
case job_type
|
|
514
618
|
when :once
|
|
515
|
-
|
|
516
|
-
|
|
619
|
+
opts[:_t] ||= Rufus::Scheduler.parse(t, opts)
|
|
620
|
+
opts[:_t].is_a?(Time) ? AtJob : InJob
|
|
517
621
|
when :every
|
|
518
622
|
EveryJob
|
|
519
623
|
when :interval
|
data/rufus-scheduler.gemspec
CHANGED
|
@@ -30,6 +30,7 @@ job scheduler for Ruby (at, cron, in and every jobs).
|
|
|
30
30
|
|
|
31
31
|
s.add_development_dependency 'rake'
|
|
32
32
|
s.add_development_dependency 'rspec', '>= 2.13.0'
|
|
33
|
+
s.add_development_dependency 'chronic'
|
|
33
34
|
|
|
34
35
|
s.require_path = 'lib'
|
|
35
36
|
|
|
@@ -49,7 +50,7 @@ A) Forget it and peg your Gemfile to rufus-scheduler 2.0.24
|
|
|
49
50
|
and / or
|
|
50
51
|
|
|
51
52
|
B) Take some time to carefully report the issue at
|
|
52
|
-
https://github.com/jmettraux/rufus-scheduler/
|
|
53
|
+
https://github.com/jmettraux/rufus-scheduler/issues
|
|
53
54
|
|
|
54
55
|
For general help about rufus-scheduler, ask via:
|
|
55
56
|
http://stackoverflow.com/questions/ask?tags=rufus-scheduler+ruby
|
data/spec/basics_spec.rb
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
|
|
2
|
+
#
|
|
3
|
+
# Specifying rufus-scheduler
|
|
4
|
+
#
|
|
5
|
+
# Sun Jun 1 05:52:24 JST 2014
|
|
6
|
+
#
|
|
7
|
+
|
|
8
|
+
require 'spec_helper'
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
describe 'basics' do
|
|
12
|
+
|
|
13
|
+
def tts(time)
|
|
14
|
+
|
|
15
|
+
time.strftime('%Y-%m-%d %H:%M:%S %z') + (time.dst? ? ' dst' : '')
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
describe 'Time.new' do
|
|
19
|
+
|
|
20
|
+
it 'accepts a timezone final argument' do
|
|
21
|
+
|
|
22
|
+
if jruby? or ruby18?
|
|
23
|
+
|
|
24
|
+
expect(true).to be(true)
|
|
25
|
+
|
|
26
|
+
else
|
|
27
|
+
|
|
28
|
+
expect(
|
|
29
|
+
tts(Time.new(2014, 1, 1, 1, 0, 0, '+01:00'))
|
|
30
|
+
).to eq('2014-01-01 01:00:00 +0100')
|
|
31
|
+
expect(
|
|
32
|
+
tts(Time.new(2014, 8, 1, 1, 0, 0, '+01:00'))
|
|
33
|
+
).to eq('2014-08-01 01:00:00 +0100')
|
|
34
|
+
expect(
|
|
35
|
+
tts(Time.new(2014, 8, 1, 1, 0, 0, '+01:00'))
|
|
36
|
+
).to eq('2014-08-01 01:00:00 +0100')
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
describe 'Time.local' do
|
|
42
|
+
|
|
43
|
+
it 'works as expected' do
|
|
44
|
+
|
|
45
|
+
expect(
|
|
46
|
+
tts(in_zone('Europe/Berlin') { Time.local(2014, 1, 1, 1, 0, 0) })
|
|
47
|
+
).to eq('2014-01-01 01:00:00 +0100')
|
|
48
|
+
expect(
|
|
49
|
+
tts(in_zone('Europe/Berlin') { Time.local(2014, 8, 1, 1, 0, 0) })
|
|
50
|
+
).to eq('2014-08-01 01:00:00 +0200 dst')
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|