rufus-scheduler 3.5.2 → 3.8.1
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +32 -0
- data/CREDITS.md +10 -0
- data/LICENSE.txt +1 -1
- data/Makefile +1 -1
- data/README.md +179 -85
- data/lib/rufus/scheduler/job_array.rb +37 -47
- data/lib/rufus/scheduler/jobs_core.rb +369 -0
- data/lib/rufus/scheduler/jobs_one_time.rb +53 -0
- data/lib/rufus/scheduler/jobs_repeat.rb +335 -0
- data/lib/rufus/scheduler/locks.rb +41 -44
- data/lib/rufus/scheduler/util.rb +166 -150
- data/lib/rufus/scheduler.rb +529 -432
- data/rufus-scheduler.gemspec +2 -3
- metadata +13 -12
- data/lib/rufus/scheduler/jobs.rb +0 -682
data/lib/rufus/scheduler.rb
CHANGED
|
@@ -1,626 +1,723 @@
|
|
|
1
1
|
|
|
2
|
-
require 'set'
|
|
3
2
|
require 'date' if RUBY_VERSION < '1.9.0'
|
|
4
|
-
require 'time'
|
|
5
3
|
require 'thread'
|
|
6
4
|
|
|
7
5
|
require 'fugit'
|
|
8
6
|
|
|
9
7
|
|
|
10
|
-
module Rufus
|
|
8
|
+
module Rufus; end
|
|
11
9
|
|
|
12
|
-
|
|
10
|
+
class Rufus::Scheduler
|
|
13
11
|
|
|
14
|
-
|
|
12
|
+
VERSION = '3.8.1'
|
|
15
13
|
|
|
16
|
-
|
|
14
|
+
EoTime = ::EtOrbi::EoTime
|
|
17
15
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
16
|
+
require 'rufus/scheduler/util'
|
|
17
|
+
require 'rufus/scheduler/jobs_core'
|
|
18
|
+
require 'rufus/scheduler/jobs_one_time'
|
|
19
|
+
require 'rufus/scheduler/jobs_repeat'
|
|
20
|
+
require 'rufus/scheduler/job_array'
|
|
21
|
+
require 'rufus/scheduler/locks'
|
|
22
22
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
23
|
+
#
|
|
24
|
+
# A common error class for rufus-scheduler
|
|
25
|
+
#
|
|
26
|
+
class Error < StandardError; end
|
|
27
27
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
28
|
+
#
|
|
29
|
+
# This error is thrown when the :timeout attribute triggers
|
|
30
|
+
#
|
|
31
|
+
class TimeoutError < Error; end
|
|
32
32
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
33
|
+
#
|
|
34
|
+
# For when the scheduler is not running
|
|
35
|
+
# (it got shut down or didn't start because of a lock)
|
|
36
|
+
#
|
|
37
|
+
class NotRunningError < Error; end
|
|
38
38
|
|
|
39
|
-
|
|
40
|
-
|
|
39
|
+
#MIN_WORK_THREADS = 3
|
|
40
|
+
MAX_WORK_THREADS = 28
|
|
41
41
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
attr_reader :thread
|
|
45
|
-
attr_reader :thread_key
|
|
46
|
-
attr_reader :mutexes
|
|
42
|
+
attr_accessor :frequency
|
|
43
|
+
attr_accessor :discard_past
|
|
47
44
|
|
|
48
|
-
|
|
49
|
-
|
|
45
|
+
attr_reader :started_at
|
|
46
|
+
attr_reader :paused_at
|
|
47
|
+
attr_reader :thread
|
|
48
|
+
attr_reader :thread_key
|
|
49
|
+
attr_reader :mutexes
|
|
50
50
|
|
|
51
|
-
|
|
51
|
+
#attr_accessor :min_work_threads
|
|
52
|
+
attr_accessor :max_work_threads
|
|
52
53
|
|
|
53
|
-
|
|
54
|
+
attr_accessor :stderr
|
|
54
55
|
|
|
55
|
-
|
|
56
|
+
attr_reader :work_queue
|
|
56
57
|
|
|
57
|
-
|
|
58
|
+
def initialize(opts={})
|
|
58
59
|
|
|
59
|
-
|
|
60
|
-
@paused = false
|
|
60
|
+
@opts = opts
|
|
61
61
|
|
|
62
|
-
|
|
62
|
+
@started_at = nil
|
|
63
|
+
@paused_at = nil
|
|
63
64
|
|
|
64
|
-
|
|
65
|
-
@mutexes = {}
|
|
65
|
+
@jobs = JobArray.new
|
|
66
66
|
|
|
67
|
-
|
|
67
|
+
@frequency = Rufus::Scheduler.parse(opts[:frequency] || 0.300)
|
|
68
|
+
@discard_past = opts.has_key?(:discard_past) ? opts[:discard_past] : true
|
|
68
69
|
|
|
69
|
-
|
|
70
|
-
@max_work_threads = opts[:max_work_threads] || MAX_WORK_THREADS
|
|
70
|
+
@mutexes = {}
|
|
71
71
|
|
|
72
|
-
|
|
72
|
+
@work_queue = Queue.new
|
|
73
|
+
@join_queue = Queue.new
|
|
73
74
|
|
|
74
|
-
|
|
75
|
+
#@min_work_threads =
|
|
76
|
+
# opts[:min_work_threads] || opts[:min_worker_threads] ||
|
|
77
|
+
# MIN_WORK_THREADS
|
|
78
|
+
@max_work_threads =
|
|
79
|
+
opts[:max_work_threads] || opts[:max_worker_threads] ||
|
|
80
|
+
MAX_WORK_THREADS
|
|
75
81
|
|
|
76
|
-
|
|
77
|
-
if lockfile = opts[:lockfile]
|
|
78
|
-
Rufus::Scheduler::FileLock.new(lockfile)
|
|
79
|
-
else
|
|
80
|
-
opts[:scheduler_lock] || Rufus::Scheduler::NullLock.new
|
|
81
|
-
end
|
|
82
|
+
@stderr = $stderr
|
|
82
83
|
|
|
83
|
-
|
|
84
|
+
@thread_key = "rufus_scheduler_#{self.object_id}"
|
|
84
85
|
|
|
85
|
-
|
|
86
|
-
|
|
86
|
+
@scheduler_lock =
|
|
87
|
+
if lockfile = opts[:lockfile]
|
|
88
|
+
Rufus::Scheduler::FileLock.new(lockfile)
|
|
89
|
+
else
|
|
90
|
+
opts[:scheduler_lock] || Rufus::Scheduler::NullLock.new
|
|
91
|
+
end
|
|
87
92
|
|
|
88
|
-
|
|
89
|
-
end
|
|
93
|
+
@trigger_lock = opts[:trigger_lock] || Rufus::Scheduler::NullLock.new
|
|
90
94
|
|
|
91
|
-
#
|
|
92
|
-
|
|
93
|
-
def self.singleton(opts={})
|
|
95
|
+
# If we can't grab the @scheduler_lock, don't run.
|
|
96
|
+
lock || return
|
|
94
97
|
|
|
95
|
-
|
|
96
|
-
|
|
98
|
+
start
|
|
99
|
+
end
|
|
97
100
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
+
# Returns a singleton Rufus::Scheduler instance
|
|
102
|
+
#
|
|
103
|
+
def self.singleton(opts={})
|
|
101
104
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
#
|
|
105
|
-
# For now, let's assume the people pointing at rufus-scheduler/master
|
|
106
|
-
# on GitHub know what they do...
|
|
107
|
-
#
|
|
108
|
-
def self.start_new
|
|
105
|
+
@singleton ||= Rufus::Scheduler.new(opts)
|
|
106
|
+
end
|
|
109
107
|
|
|
110
|
-
|
|
111
|
-
|
|
108
|
+
# Alias for Rufus::Scheduler.singleton
|
|
109
|
+
#
|
|
110
|
+
def self.s(opts={}); singleton(opts); end
|
|
112
111
|
|
|
113
|
-
|
|
112
|
+
# Releasing the gem would probably require redirecting .start_new to
|
|
113
|
+
# .new and emit a simple deprecation message.
|
|
114
|
+
#
|
|
115
|
+
# For now, let's assume the people pointing at rufus-scheduler/master
|
|
116
|
+
# on GitHub know what they do...
|
|
117
|
+
#
|
|
118
|
+
def self.start_new
|
|
114
119
|
|
|
115
|
-
|
|
120
|
+
fail 'this is rufus-scheduler 3.x, use .new instead of .start_new'
|
|
121
|
+
end
|
|
116
122
|
|
|
117
|
-
|
|
118
|
-
# provokes https://github.com/jmettraux/rufus-scheduler/issue/98
|
|
119
|
-
@jobs.array.each { |j| j.unschedule }
|
|
123
|
+
def uptime
|
|
120
124
|
|
|
121
|
-
|
|
125
|
+
@started_at ? EoTime.now - @started_at : nil
|
|
126
|
+
end
|
|
122
127
|
|
|
123
|
-
|
|
124
|
-
join_all_work_threads
|
|
125
|
-
elsif opt == :kill
|
|
126
|
-
kill_all_work_threads
|
|
127
|
-
end
|
|
128
|
+
def around_trigger(job)
|
|
128
129
|
|
|
129
|
-
|
|
130
|
-
|
|
130
|
+
yield
|
|
131
|
+
end
|
|
131
132
|
|
|
132
|
-
|
|
133
|
+
def uptime_s
|
|
133
134
|
|
|
134
|
-
|
|
135
|
+
uptime ? self.class.to_duration(uptime) : ''
|
|
136
|
+
end
|
|
135
137
|
|
|
136
|
-
|
|
137
|
-
end
|
|
138
|
+
def join(time_limit=nil)
|
|
138
139
|
|
|
139
|
-
|
|
140
|
+
fail NotRunningError.new('cannot join scheduler that is not running') \
|
|
141
|
+
unless @thread
|
|
142
|
+
fail ThreadError.new('scheduler thread cannot join itself') \
|
|
143
|
+
if @thread == Thread.current
|
|
140
144
|
|
|
141
|
-
|
|
145
|
+
if time_limit
|
|
146
|
+
time_limit_join(time_limit)
|
|
147
|
+
else
|
|
148
|
+
no_time_limit_join
|
|
142
149
|
end
|
|
150
|
+
end
|
|
143
151
|
|
|
144
|
-
|
|
152
|
+
def down?
|
|
145
153
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
) unless @thread
|
|
154
|
+
! @started_at
|
|
155
|
+
end
|
|
149
156
|
|
|
150
|
-
|
|
151
|
-
end
|
|
157
|
+
def up?
|
|
152
158
|
|
|
153
|
-
|
|
159
|
+
!! @started_at
|
|
160
|
+
end
|
|
154
161
|
|
|
155
|
-
|
|
156
|
-
end
|
|
162
|
+
def paused?
|
|
157
163
|
|
|
158
|
-
|
|
164
|
+
!! @paused_at
|
|
165
|
+
end
|
|
159
166
|
|
|
160
|
-
|
|
161
|
-
end
|
|
167
|
+
def pause
|
|
162
168
|
|
|
163
|
-
|
|
169
|
+
@paused_at = EoTime.now
|
|
170
|
+
end
|
|
164
171
|
|
|
165
|
-
|
|
166
|
-
end
|
|
172
|
+
def resume(opts={})
|
|
167
173
|
|
|
168
|
-
|
|
174
|
+
dp = opts[:discard_past]
|
|
175
|
+
jobs.each { |job| job.resume_discard_past = dp }
|
|
169
176
|
|
|
170
|
-
|
|
171
|
-
|
|
177
|
+
@paused_at = nil
|
|
178
|
+
end
|
|
172
179
|
|
|
173
|
-
|
|
180
|
+
#--
|
|
181
|
+
# scheduling methods
|
|
182
|
+
#++
|
|
174
183
|
|
|
175
|
-
|
|
176
|
-
end
|
|
184
|
+
def at(time, callable=nil, opts={}, &block)
|
|
177
185
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
#++
|
|
186
|
+
do_schedule(:once, time, callable, opts, opts[:job], block)
|
|
187
|
+
end
|
|
181
188
|
|
|
182
|
-
|
|
189
|
+
def schedule_at(time, callable=nil, opts={}, &block)
|
|
183
190
|
|
|
184
|
-
|
|
185
|
-
|
|
191
|
+
do_schedule(:once, time, callable, opts, true, block)
|
|
192
|
+
end
|
|
186
193
|
|
|
187
|
-
|
|
194
|
+
def in(duration, callable=nil, opts={}, &block)
|
|
188
195
|
|
|
189
|
-
|
|
190
|
-
|
|
196
|
+
do_schedule(:once, duration, callable, opts, opts[:job], block)
|
|
197
|
+
end
|
|
191
198
|
|
|
192
|
-
|
|
199
|
+
def schedule_in(duration, callable=nil, opts={}, &block)
|
|
193
200
|
|
|
194
|
-
|
|
195
|
-
|
|
201
|
+
do_schedule(:once, duration, callable, opts, true, block)
|
|
202
|
+
end
|
|
196
203
|
|
|
197
|
-
|
|
204
|
+
def every(duration, callable=nil, opts={}, &block)
|
|
198
205
|
|
|
199
|
-
|
|
200
|
-
|
|
206
|
+
do_schedule(:every, duration, callable, opts, opts[:job], block)
|
|
207
|
+
end
|
|
201
208
|
|
|
202
|
-
|
|
209
|
+
def schedule_every(duration, callable=nil, opts={}, &block)
|
|
203
210
|
|
|
204
|
-
|
|
205
|
-
|
|
211
|
+
do_schedule(:every, duration, callable, opts, true, block)
|
|
212
|
+
end
|
|
206
213
|
|
|
207
|
-
|
|
214
|
+
def interval(duration, callable=nil, opts={}, &block)
|
|
208
215
|
|
|
209
|
-
|
|
210
|
-
|
|
216
|
+
do_schedule(:interval, duration, callable, opts, opts[:job], block)
|
|
217
|
+
end
|
|
211
218
|
|
|
212
|
-
|
|
219
|
+
def schedule_interval(duration, callable=nil, opts={}, &block)
|
|
213
220
|
|
|
214
|
-
|
|
215
|
-
|
|
221
|
+
do_schedule(:interval, duration, callable, opts, true, block)
|
|
222
|
+
end
|
|
216
223
|
|
|
217
|
-
|
|
224
|
+
def cron(cronline, callable=nil, opts={}, &block)
|
|
218
225
|
|
|
219
|
-
|
|
220
|
-
|
|
226
|
+
do_schedule(:cron, cronline, callable, opts, opts[:job], block)
|
|
227
|
+
end
|
|
221
228
|
|
|
222
|
-
|
|
229
|
+
def schedule_cron(cronline, callable=nil, opts={}, &block)
|
|
223
230
|
|
|
224
|
-
|
|
225
|
-
|
|
231
|
+
do_schedule(:cron, cronline, callable, opts, true, block)
|
|
232
|
+
end
|
|
233
|
+
|
|
234
|
+
def schedule(arg, callable=nil, opts={}, &block)
|
|
226
235
|
|
|
227
|
-
|
|
236
|
+
callable, opts = nil, callable if callable.is_a?(Hash)
|
|
237
|
+
opts = opts.dup
|
|
228
238
|
|
|
229
|
-
|
|
239
|
+
opts[:_t] = Rufus::Scheduler.parse(arg, opts)
|
|
240
|
+
|
|
241
|
+
case opts[:_t]
|
|
242
|
+
when ::Fugit::Cron then schedule_cron(arg, callable, opts, &block)
|
|
243
|
+
when ::EtOrbi::EoTime, Time then schedule_at(arg, callable, opts, &block)
|
|
244
|
+
else schedule_in(arg, callable, opts, &block)
|
|
230
245
|
end
|
|
246
|
+
end
|
|
231
247
|
|
|
232
|
-
|
|
248
|
+
def repeat(arg, callable=nil, opts={}, &block)
|
|
233
249
|
|
|
234
|
-
|
|
235
|
-
|
|
250
|
+
callable, opts = nil, callable if callable.is_a?(Hash)
|
|
251
|
+
opts = opts.dup
|
|
236
252
|
|
|
237
|
-
|
|
253
|
+
opts[:_t] = Rufus::Scheduler.parse(arg, opts)
|
|
238
254
|
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
else schedule_in(arg, callable, opts, &block)
|
|
243
|
-
end
|
|
255
|
+
case opts[:_t]
|
|
256
|
+
when ::Fugit::Cron then schedule_cron(arg, callable, opts, &block)
|
|
257
|
+
else schedule_every(arg, callable, opts, &block)
|
|
244
258
|
end
|
|
259
|
+
end
|
|
245
260
|
|
|
246
|
-
|
|
261
|
+
def unschedule(job_or_job_id)
|
|
247
262
|
|
|
248
|
-
|
|
249
|
-
opts = opts.dup
|
|
263
|
+
job, job_id = fetch(job_or_job_id)
|
|
250
264
|
|
|
251
|
-
|
|
265
|
+
fail ArgumentError.new("no job found with id '#{job_id}'") unless job
|
|
252
266
|
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
267
|
+
job.unschedule if job
|
|
268
|
+
end
|
|
269
|
+
|
|
270
|
+
#--
|
|
271
|
+
# jobs methods
|
|
272
|
+
#++
|
|
258
273
|
|
|
259
|
-
|
|
274
|
+
# Returns all the scheduled jobs
|
|
275
|
+
# (even those right before re-schedule).
|
|
276
|
+
#
|
|
277
|
+
def jobs(opts={})
|
|
260
278
|
|
|
261
|
-
|
|
279
|
+
opts = { opts => true } if opts.is_a?(Symbol)
|
|
262
280
|
|
|
263
|
-
|
|
281
|
+
jobs = @jobs.to_a
|
|
264
282
|
|
|
265
|
-
|
|
283
|
+
if opts[:running]
|
|
284
|
+
jobs = jobs.select { |j| j.running? }
|
|
285
|
+
elsif ! opts[:all]
|
|
286
|
+
jobs = jobs.reject { |j| j.next_time.nil? || j.unscheduled_at }
|
|
266
287
|
end
|
|
267
288
|
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
289
|
+
tags = Array(opts[:tag] || opts[:tags]).collect(&:to_s)
|
|
290
|
+
jobs = jobs.reject { |j| tags.find { |t| ! j.tags.include?(t) } }
|
|
291
|
+
|
|
292
|
+
jobs
|
|
293
|
+
end
|
|
271
294
|
|
|
272
|
-
|
|
273
|
-
# (even those right before re-schedule).
|
|
274
|
-
#
|
|
275
|
-
def jobs(opts={})
|
|
295
|
+
def at_jobs(opts={})
|
|
276
296
|
|
|
277
|
-
|
|
297
|
+
jobs(opts).select { |j| j.is_a?(Rufus::Scheduler::AtJob) }
|
|
298
|
+
end
|
|
278
299
|
|
|
279
|
-
|
|
300
|
+
def in_jobs(opts={})
|
|
280
301
|
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
elsif ! opts[:all]
|
|
284
|
-
jobs = jobs.reject { |j| j.next_time.nil? || j.unscheduled_at }
|
|
285
|
-
end
|
|
302
|
+
jobs(opts).select { |j| j.is_a?(Rufus::Scheduler::InJob) }
|
|
303
|
+
end
|
|
286
304
|
|
|
287
|
-
|
|
288
|
-
jobs = jobs.reject { |j| tags.find { |t| ! j.tags.include?(t) } }
|
|
305
|
+
def every_jobs(opts={})
|
|
289
306
|
|
|
290
|
-
|
|
291
|
-
|
|
307
|
+
jobs(opts).select { |j| j.is_a?(Rufus::Scheduler::EveryJob) }
|
|
308
|
+
end
|
|
292
309
|
|
|
293
|
-
|
|
310
|
+
def interval_jobs(opts={})
|
|
294
311
|
|
|
295
|
-
|
|
296
|
-
|
|
312
|
+
jobs(opts).select { |j| j.is_a?(Rufus::Scheduler::IntervalJob) }
|
|
313
|
+
end
|
|
297
314
|
|
|
298
|
-
|
|
315
|
+
def cron_jobs(opts={})
|
|
299
316
|
|
|
300
|
-
|
|
301
|
-
|
|
317
|
+
jobs(opts).select { |j| j.is_a?(Rufus::Scheduler::CronJob) }
|
|
318
|
+
end
|
|
302
319
|
|
|
303
|
-
|
|
320
|
+
def job(job_id)
|
|
304
321
|
|
|
305
|
-
|
|
306
|
-
|
|
322
|
+
@jobs[job_id]
|
|
323
|
+
end
|
|
307
324
|
|
|
308
|
-
|
|
325
|
+
# Returns true if the scheduler has acquired the [exclusive] lock and
|
|
326
|
+
# thus may run.
|
|
327
|
+
#
|
|
328
|
+
# Most of the time, a scheduler is run alone and this method should
|
|
329
|
+
# return true. It is useful in cases where among a group of applications
|
|
330
|
+
# only one of them should run the scheduler. For schedulers that should
|
|
331
|
+
# not run, the method should return false.
|
|
332
|
+
#
|
|
333
|
+
# Out of the box, rufus-scheduler proposes the
|
|
334
|
+
# :lockfile => 'path/to/lock/file' scheduler start option. It makes
|
|
335
|
+
# it easy for schedulers on the same machine to determine which should
|
|
336
|
+
# run (the first to write the lockfile and lock it). It uses "man 2 flock"
|
|
337
|
+
# so it probably won't work reliably on distributed file systems.
|
|
338
|
+
#
|
|
339
|
+
# If one needs to use a special/different locking mechanism, the scheduler
|
|
340
|
+
# accepts :scheduler_lock => lock_object. lock_object only needs to respond
|
|
341
|
+
# to #lock
|
|
342
|
+
# and #unlock, and both of these methods should be idempotent.
|
|
343
|
+
#
|
|
344
|
+
# Look at rufus/scheduler/locks.rb for an example.
|
|
345
|
+
#
|
|
346
|
+
def lock
|
|
347
|
+
|
|
348
|
+
@scheduler_lock.lock
|
|
349
|
+
end
|
|
309
350
|
|
|
310
|
-
|
|
311
|
-
|
|
351
|
+
# Sister method to #lock, is called when the scheduler shuts down.
|
|
352
|
+
#
|
|
353
|
+
def unlock
|
|
312
354
|
|
|
313
|
-
|
|
355
|
+
@trigger_lock.unlock
|
|
356
|
+
@scheduler_lock.unlock
|
|
357
|
+
end
|
|
314
358
|
|
|
315
|
-
|
|
316
|
-
|
|
359
|
+
# Callback called when a job is triggered. If the lock cannot be acquired,
|
|
360
|
+
# the job won't run (though it'll still be scheduled to run again if
|
|
361
|
+
# necessary).
|
|
362
|
+
#
|
|
363
|
+
def confirm_lock
|
|
317
364
|
|
|
318
|
-
|
|
365
|
+
@trigger_lock.lock
|
|
366
|
+
end
|
|
319
367
|
|
|
320
|
-
|
|
321
|
-
|
|
368
|
+
# Returns true if this job is currently scheduled.
|
|
369
|
+
#
|
|
370
|
+
# Takes extra care to answer true if the job is a repeat job
|
|
371
|
+
# currently firing.
|
|
372
|
+
#
|
|
373
|
+
def scheduled?(job_or_job_id)
|
|
322
374
|
|
|
323
|
-
|
|
324
|
-
# thus may run.
|
|
325
|
-
#
|
|
326
|
-
# Most of the time, a scheduler is run alone and this method should
|
|
327
|
-
# return true. It is useful in cases where among a group of applications
|
|
328
|
-
# only one of them should run the scheduler. For schedulers that should
|
|
329
|
-
# not run, the method should return false.
|
|
330
|
-
#
|
|
331
|
-
# Out of the box, rufus-scheduler proposes the
|
|
332
|
-
# :lockfile => 'path/to/lock/file' scheduler start option. It makes
|
|
333
|
-
# it easy for schedulers on the same machine to determine which should
|
|
334
|
-
# run (the first to write the lockfile and lock it). It uses "man 2 flock"
|
|
335
|
-
# so it probably won't work reliably on distributed file systems.
|
|
336
|
-
#
|
|
337
|
-
# If one needs to use a special/different locking mechanism, the scheduler
|
|
338
|
-
# accepts :scheduler_lock => lock_object. lock_object only needs to respond
|
|
339
|
-
# to #lock
|
|
340
|
-
# and #unlock, and both of these methods should be idempotent.
|
|
341
|
-
#
|
|
342
|
-
# Look at rufus/scheduler/locks.rb for an example.
|
|
343
|
-
#
|
|
344
|
-
def lock
|
|
345
|
-
|
|
346
|
-
@scheduler_lock.lock
|
|
347
|
-
end
|
|
375
|
+
job, _ = fetch(job_or_job_id)
|
|
348
376
|
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
def unlock
|
|
377
|
+
!! (job && job.unscheduled_at.nil? && job.next_time != nil)
|
|
378
|
+
end
|
|
352
379
|
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
380
|
+
# Lists all the threads associated with this scheduler.
|
|
381
|
+
#
|
|
382
|
+
def threads
|
|
356
383
|
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
# necessary).
|
|
360
|
-
#
|
|
361
|
-
def confirm_lock
|
|
384
|
+
Thread.list.select { |t| t[thread_key] }
|
|
385
|
+
end
|
|
362
386
|
|
|
363
|
-
|
|
387
|
+
# Lists all the work threads (the ones actually running the scheduled
|
|
388
|
+
# block code)
|
|
389
|
+
#
|
|
390
|
+
# Accepts a query option, which can be set to:
|
|
391
|
+
# * :all (default), returns all the threads that are work threads
|
|
392
|
+
# or are currently running a job
|
|
393
|
+
# * :active, returns all threads that are currently running a job
|
|
394
|
+
# * :vacant, returns the threads that are not running a job
|
|
395
|
+
#
|
|
396
|
+
# If, thanks to :blocking => true, a job is scheduled to monopolize the
|
|
397
|
+
# main scheduler thread, that thread will get returned when :active or
|
|
398
|
+
# :all.
|
|
399
|
+
#
|
|
400
|
+
def work_threads(query=:all)
|
|
401
|
+
|
|
402
|
+
ts = threads.select { |t| t[:rufus_scheduler_work_thread] }
|
|
403
|
+
|
|
404
|
+
case query
|
|
405
|
+
when :active then ts.select { |t| t[:rufus_scheduler_job] }
|
|
406
|
+
when :vacant then ts.reject { |t| t[:rufus_scheduler_job] }
|
|
407
|
+
else ts
|
|
364
408
|
end
|
|
409
|
+
end
|
|
365
410
|
|
|
366
|
-
|
|
367
|
-
#
|
|
368
|
-
# Takes extra care to answer true if the job is a repeat job
|
|
369
|
-
# currently firing.
|
|
370
|
-
#
|
|
371
|
-
def scheduled?(job_or_job_id)
|
|
411
|
+
def running_jobs(opts={})
|
|
372
412
|
|
|
373
|
-
|
|
413
|
+
jobs(opts.merge(:running => true))
|
|
414
|
+
end
|
|
374
415
|
|
|
375
|
-
|
|
376
|
-
end
|
|
416
|
+
def occurrences(time0, time1, format=:per_job)
|
|
377
417
|
|
|
378
|
-
|
|
379
|
-
#
|
|
380
|
-
def threads
|
|
418
|
+
h = {}
|
|
381
419
|
|
|
382
|
-
|
|
420
|
+
jobs.each do |j|
|
|
421
|
+
os = j.occurrences(time0, time1)
|
|
422
|
+
h[j] = os if os.any?
|
|
383
423
|
end
|
|
384
424
|
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
# * :active, returns all threads that are currently running a job
|
|
392
|
-
# * :vacant, returns the threads that are not running a job
|
|
393
|
-
#
|
|
394
|
-
# If, thanks to :blocking => true, a job is scheduled to monopolize the
|
|
395
|
-
# main scheduler thread, that thread will get returned when :active or
|
|
396
|
-
# :all.
|
|
397
|
-
#
|
|
398
|
-
def work_threads(query=:all)
|
|
399
|
-
|
|
400
|
-
ts = threads.select { |t| t[:rufus_scheduler_work_thread] }
|
|
401
|
-
|
|
402
|
-
case query
|
|
403
|
-
when :active then ts.select { |t| t[:rufus_scheduler_job] }
|
|
404
|
-
when :vacant then ts.reject { |t| t[:rufus_scheduler_job] }
|
|
405
|
-
else ts
|
|
406
|
-
end
|
|
425
|
+
if format == :timeline
|
|
426
|
+
a = []
|
|
427
|
+
h.each { |j, ts| ts.each { |t| a << [ t, j ] } }
|
|
428
|
+
a.sort_by { |(t, _)| t }
|
|
429
|
+
else
|
|
430
|
+
h
|
|
407
431
|
end
|
|
432
|
+
end
|
|
408
433
|
|
|
409
|
-
|
|
434
|
+
def timeline(time0, time1)
|
|
410
435
|
|
|
411
|
-
|
|
412
|
-
|
|
436
|
+
occurrences(time0, time1, :timeline)
|
|
437
|
+
end
|
|
413
438
|
|
|
414
|
-
|
|
439
|
+
def on_error(job, err)
|
|
440
|
+
|
|
441
|
+
pre = err.object_id.to_s
|
|
442
|
+
|
|
443
|
+
ms = {}; mutexes.each { |k, v| ms[k] = v.locked? }
|
|
444
|
+
|
|
445
|
+
stderr.puts("{ #{pre} rufus-scheduler intercepted an error:")
|
|
446
|
+
stderr.puts(" #{pre} job:")
|
|
447
|
+
stderr.puts(" #{pre} #{job.class} #{job.original.inspect} #{job.opts.inspect}")
|
|
448
|
+
stderr.puts(" #{pre} #{job.source_location.inspect}")
|
|
449
|
+
# TODO: eventually use a Job#detail or something like that
|
|
450
|
+
stderr.puts(" #{pre} error:")
|
|
451
|
+
stderr.puts(" #{pre} #{err.object_id}")
|
|
452
|
+
stderr.puts(" #{pre} #{err.class}")
|
|
453
|
+
stderr.puts(" #{pre} #{err}")
|
|
454
|
+
err.backtrace.each do |l|
|
|
455
|
+
stderr.puts(" #{pre} #{l}")
|
|
456
|
+
end
|
|
457
|
+
stderr.puts(" #{pre} tz:")
|
|
458
|
+
stderr.puts(" #{pre} ENV['TZ']: #{ENV['TZ']}")
|
|
459
|
+
stderr.puts(" #{pre} Time.now: #{Time.now}")
|
|
460
|
+
stderr.puts(" #{pre} local_tzone: #{EoTime.local_tzone.inspect}")
|
|
461
|
+
stderr.puts(" #{pre} et-orbi:")
|
|
462
|
+
stderr.puts(" #{pre} #{EoTime.platform_info}")
|
|
463
|
+
stderr.puts(" #{pre} scheduler:")
|
|
464
|
+
stderr.puts(" #{pre} object_id: #{object_id}")
|
|
465
|
+
stderr.puts(" #{pre} opts:")
|
|
466
|
+
stderr.puts(" #{pre} #{@opts.inspect}")
|
|
467
|
+
stderr.puts(" #{pre} frequency: #{self.frequency}")
|
|
468
|
+
stderr.puts(" #{pre} scheduler_lock: #{@scheduler_lock.inspect}")
|
|
469
|
+
stderr.puts(" #{pre} trigger_lock: #{@trigger_lock.inspect}")
|
|
470
|
+
stderr.puts(" #{pre} uptime: #{uptime} (#{uptime_s})")
|
|
471
|
+
stderr.puts(" #{pre} down?: #{down?}")
|
|
472
|
+
stderr.puts(" #{pre} frequency: #{frequency.inspect}")
|
|
473
|
+
stderr.puts(" #{pre} discard_past: #{discard_past.inspect}")
|
|
474
|
+
stderr.puts(" #{pre} started_at: #{started_at.inspect}")
|
|
475
|
+
stderr.puts(" #{pre} paused_at: #{paused_at.inspect}")
|
|
476
|
+
stderr.puts(" #{pre} threads: #{self.threads.size}")
|
|
477
|
+
stderr.puts(" #{pre} thread: #{self.thread}")
|
|
478
|
+
stderr.puts(" #{pre} thread_key: #{self.thread_key}")
|
|
479
|
+
stderr.puts(" #{pre} work_threads: #{work_threads.size}")
|
|
480
|
+
stderr.puts(" #{pre} active: #{work_threads(:active).size}")
|
|
481
|
+
stderr.puts(" #{pre} vacant: #{work_threads(:vacant).size}")
|
|
482
|
+
stderr.puts(" #{pre} max_work_threads: #{max_work_threads}")
|
|
483
|
+
stderr.puts(" #{pre} mutexes: #{ms.inspect}")
|
|
484
|
+
stderr.puts(" #{pre} jobs: #{jobs.size}")
|
|
485
|
+
stderr.puts(" #{pre} at_jobs: #{at_jobs.size}")
|
|
486
|
+
stderr.puts(" #{pre} in_jobs: #{in_jobs.size}")
|
|
487
|
+
stderr.puts(" #{pre} every_jobs: #{every_jobs.size}")
|
|
488
|
+
stderr.puts(" #{pre} interval_jobs: #{interval_jobs.size}")
|
|
489
|
+
stderr.puts(" #{pre} cron_jobs: #{cron_jobs.size}")
|
|
490
|
+
stderr.puts(" #{pre} running_jobs: #{running_jobs.size}")
|
|
491
|
+
stderr.puts(" #{pre} work_queue:")
|
|
492
|
+
stderr.puts(" #{pre} size: #{@work_queue.size}")
|
|
493
|
+
stderr.puts(" #{pre} num_waiting: #{@work_queue.num_waiting}")
|
|
494
|
+
stderr.puts(" #{pre} join_queue:")
|
|
495
|
+
stderr.puts(" #{pre} size: #{@join_queue.size}")
|
|
496
|
+
stderr.puts(" #{pre} num_waiting: #{@join_queue.num_waiting}")
|
|
497
|
+
stderr.puts("} #{pre} .")
|
|
498
|
+
|
|
499
|
+
rescue => e
|
|
500
|
+
|
|
501
|
+
stderr.puts("failure in #on_error itself:")
|
|
502
|
+
stderr.puts(e.inspect)
|
|
503
|
+
stderr.puts(e.backtrace)
|
|
504
|
+
|
|
505
|
+
ensure
|
|
506
|
+
|
|
507
|
+
stderr.flush
|
|
508
|
+
end
|
|
415
509
|
|
|
416
|
-
|
|
510
|
+
def shutdown(opt=nil)
|
|
417
511
|
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
512
|
+
opts =
|
|
513
|
+
case opt
|
|
514
|
+
when Symbol then { opt => true }
|
|
515
|
+
when Hash then opt
|
|
516
|
+
else {}
|
|
421
517
|
end
|
|
422
518
|
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
519
|
+
@jobs.unschedule_all
|
|
520
|
+
|
|
521
|
+
if opts[:wait] || opts[:join]
|
|
522
|
+
join_shutdown(opts)
|
|
523
|
+
elsif opts[:kill]
|
|
524
|
+
kill_shutdown(opts)
|
|
525
|
+
else
|
|
526
|
+
regular_shutdown(opts)
|
|
430
527
|
end
|
|
431
528
|
|
|
432
|
-
|
|
529
|
+
@work_queue.clear
|
|
433
530
|
|
|
434
|
-
|
|
435
|
-
end
|
|
531
|
+
unlock
|
|
436
532
|
|
|
437
|
-
|
|
533
|
+
@thread.join
|
|
534
|
+
end
|
|
535
|
+
alias stop shutdown
|
|
438
536
|
|
|
439
|
-
|
|
537
|
+
protected
|
|
440
538
|
|
|
441
|
-
|
|
539
|
+
def join_shutdown(opts)
|
|
442
540
|
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
stderr.puts(" #{pre} #{job.class} #{job.original.inspect} #{job.opts.inspect}")
|
|
446
|
-
# TODO: eventually use a Job#detail or something like that
|
|
447
|
-
stderr.puts(" #{pre} error:")
|
|
448
|
-
stderr.puts(" #{pre} #{err.object_id}")
|
|
449
|
-
stderr.puts(" #{pre} #{err.class}")
|
|
450
|
-
stderr.puts(" #{pre} #{err}")
|
|
451
|
-
err.backtrace.each do |l|
|
|
452
|
-
stderr.puts(" #{pre} #{l}")
|
|
453
|
-
end
|
|
454
|
-
stderr.puts(" #{pre} tz:")
|
|
455
|
-
stderr.puts(" #{pre} ENV['TZ']: #{ENV['TZ']}")
|
|
456
|
-
stderr.puts(" #{pre} Time.now: #{Time.now}")
|
|
457
|
-
stderr.puts(" #{pre} local_tzone: #{EoTime.local_tzone.inspect}")
|
|
458
|
-
stderr.puts(" #{pre} et-orbi:")
|
|
459
|
-
stderr.puts(" #{pre} #{EoTime.platform_info}")
|
|
460
|
-
stderr.puts(" #{pre} scheduler:")
|
|
461
|
-
stderr.puts(" #{pre} object_id: #{object_id}")
|
|
462
|
-
stderr.puts(" #{pre} opts:")
|
|
463
|
-
stderr.puts(" #{pre} #{@opts.inspect}")
|
|
464
|
-
stderr.puts(" #{pre} frequency: #{self.frequency}")
|
|
465
|
-
stderr.puts(" #{pre} scheduler_lock: #{@scheduler_lock.inspect}")
|
|
466
|
-
stderr.puts(" #{pre} trigger_lock: #{@trigger_lock.inspect}")
|
|
467
|
-
stderr.puts(" #{pre} uptime: #{uptime} (#{uptime_s})")
|
|
468
|
-
stderr.puts(" #{pre} down?: #{down?}")
|
|
469
|
-
stderr.puts(" #{pre} threads: #{self.threads.size}")
|
|
470
|
-
stderr.puts(" #{pre} thread: #{self.thread}")
|
|
471
|
-
stderr.puts(" #{pre} thread_key: #{self.thread_key}")
|
|
472
|
-
stderr.puts(" #{pre} work_threads: #{work_threads.size}")
|
|
473
|
-
stderr.puts(" #{pre} active: #{work_threads(:active).size}")
|
|
474
|
-
stderr.puts(" #{pre} vacant: #{work_threads(:vacant).size}")
|
|
475
|
-
stderr.puts(" #{pre} max_work_threads: #{max_work_threads}")
|
|
476
|
-
stderr.puts(" #{pre} mutexes: #{ms.inspect}")
|
|
477
|
-
stderr.puts(" #{pre} jobs: #{jobs.size}")
|
|
478
|
-
stderr.puts(" #{pre} at_jobs: #{at_jobs.size}")
|
|
479
|
-
stderr.puts(" #{pre} in_jobs: #{in_jobs.size}")
|
|
480
|
-
stderr.puts(" #{pre} every_jobs: #{every_jobs.size}")
|
|
481
|
-
stderr.puts(" #{pre} interval_jobs: #{interval_jobs.size}")
|
|
482
|
-
stderr.puts(" #{pre} cron_jobs: #{cron_jobs.size}")
|
|
483
|
-
stderr.puts(" #{pre} running_jobs: #{running_jobs.size}")
|
|
484
|
-
stderr.puts(" #{pre} work_queue: #{work_queue.size}")
|
|
485
|
-
stderr.puts("} #{pre} .")
|
|
486
|
-
|
|
487
|
-
rescue => e
|
|
488
|
-
|
|
489
|
-
stderr.puts("failure in #on_error itself:")
|
|
490
|
-
stderr.puts(e.inspect)
|
|
491
|
-
stderr.puts(e.backtrace)
|
|
492
|
-
|
|
493
|
-
ensure
|
|
494
|
-
|
|
495
|
-
stderr.flush
|
|
496
|
-
end
|
|
541
|
+
limit = opts[:wait] || opts[:join]
|
|
542
|
+
limit = limit.is_a?(Numeric) ? limit : nil
|
|
497
543
|
|
|
498
|
-
|
|
544
|
+
#@started_at = nil
|
|
545
|
+
#
|
|
546
|
+
# when @started_at is nil, the scheduler thread exits, here
|
|
547
|
+
# we want it to exit when all the work threads have been joined
|
|
548
|
+
# hence it's set to nil later on
|
|
549
|
+
#
|
|
550
|
+
@paused_at = EoTime.now
|
|
499
551
|
|
|
500
|
-
|
|
501
|
-
#
|
|
502
|
-
def fetch(job_or_job_id)
|
|
552
|
+
(work_threads.size * 2 + 1).times { @work_queue << :shutdown }
|
|
503
553
|
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
end
|
|
554
|
+
work_threads
|
|
555
|
+
.collect { |wt|
|
|
556
|
+
wt == Thread.current ? nil : Thread.new { wt.join(limit); wt.kill } }
|
|
557
|
+
.each { |st|
|
|
558
|
+
st.join if st }
|
|
510
559
|
|
|
511
|
-
|
|
560
|
+
@started_at = nil
|
|
561
|
+
end
|
|
512
562
|
|
|
513
|
-
|
|
563
|
+
def kill_shutdown(opts)
|
|
514
564
|
|
|
515
|
-
|
|
516
|
-
|
|
565
|
+
@started_at = nil
|
|
566
|
+
work_threads.each(&:kill)
|
|
567
|
+
end
|
|
568
|
+
|
|
569
|
+
def regular_shutdown(opts)
|
|
570
|
+
|
|
571
|
+
@started_at = nil
|
|
572
|
+
end
|
|
517
573
|
|
|
518
|
-
|
|
574
|
+
def time_limit_join(limit)
|
|
519
575
|
|
|
520
|
-
|
|
576
|
+
fail ArgumentError.new("limit #{limit.inspect} should be > 0") \
|
|
577
|
+
unless limit.is_a?(Numeric) && limit > 0
|
|
521
578
|
|
|
522
|
-
|
|
579
|
+
t0 = monow
|
|
580
|
+
f = [ limit.to_f / 20, 0.100 ].min
|
|
523
581
|
|
|
524
|
-
|
|
582
|
+
while monow - t0 < limit
|
|
583
|
+
r =
|
|
584
|
+
begin
|
|
585
|
+
@join_queue.pop(true)
|
|
586
|
+
rescue ThreadError
|
|
587
|
+
# #<ThreadError: queue empty>
|
|
588
|
+
false
|
|
589
|
+
end
|
|
590
|
+
return r if r
|
|
591
|
+
sleep(f)
|
|
525
592
|
end
|
|
526
593
|
|
|
527
|
-
|
|
594
|
+
nil
|
|
595
|
+
end
|
|
596
|
+
|
|
597
|
+
def no_time_limit_join
|
|
598
|
+
|
|
599
|
+
@join_queue.pop
|
|
600
|
+
end
|
|
601
|
+
|
|
602
|
+
# Returns [ job, job_id ]
|
|
603
|
+
#
|
|
604
|
+
def fetch(job_or_job_id)
|
|
528
605
|
|
|
529
|
-
|
|
606
|
+
if job_or_job_id.respond_to?(:job_id)
|
|
607
|
+
[ job_or_job_id, job_or_job_id.job_id ]
|
|
608
|
+
else
|
|
609
|
+
[ job(job_or_job_id), job_or_job_id ]
|
|
530
610
|
end
|
|
611
|
+
end
|
|
612
|
+
|
|
613
|
+
def terminate_all_jobs
|
|
531
614
|
|
|
532
|
-
|
|
533
|
-
#
|
|
534
|
-
# work_threads.each { |t| t.raise(KillSignal) }
|
|
535
|
-
#end
|
|
615
|
+
jobs.each { |j| j.unschedule }
|
|
536
616
|
|
|
537
|
-
|
|
617
|
+
sleep 0.01 while running_jobs.size > 0
|
|
618
|
+
end
|
|
619
|
+
|
|
620
|
+
#def free_all_work_threads
|
|
621
|
+
#
|
|
622
|
+
# work_threads.each { |t| t.raise(KillSignal) }
|
|
623
|
+
#end
|
|
538
624
|
|
|
539
|
-
|
|
625
|
+
def start
|
|
540
626
|
|
|
541
|
-
|
|
542
|
-
Thread.new do
|
|
627
|
+
@started_at = EoTime.now
|
|
543
628
|
|
|
544
|
-
|
|
629
|
+
@thread =
|
|
630
|
+
Thread.new do
|
|
545
631
|
|
|
546
|
-
|
|
547
|
-
trigger_jobs unless @paused
|
|
548
|
-
timeout_jobs
|
|
632
|
+
while @started_at do
|
|
549
633
|
|
|
550
|
-
|
|
551
|
-
|
|
634
|
+
unschedule_jobs
|
|
635
|
+
trigger_jobs unless @paused_at
|
|
636
|
+
timeout_jobs
|
|
637
|
+
|
|
638
|
+
sleep(@frequency)
|
|
552
639
|
end
|
|
553
640
|
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
641
|
+
rejoin
|
|
642
|
+
end
|
|
643
|
+
|
|
644
|
+
@thread[@thread_key] = true
|
|
645
|
+
@thread[:rufus_scheduler] = self
|
|
646
|
+
@thread[:name] = @opts[:thread_name] || "#{@thread_key}_scheduler"
|
|
647
|
+
end
|
|
558
648
|
|
|
559
|
-
|
|
649
|
+
def unschedule_jobs
|
|
560
650
|
|
|
561
|
-
|
|
562
|
-
|
|
651
|
+
@jobs.delete_unscheduled
|
|
652
|
+
end
|
|
563
653
|
|
|
564
|
-
|
|
654
|
+
def trigger_jobs
|
|
565
655
|
|
|
566
|
-
|
|
656
|
+
now = EoTime.now
|
|
567
657
|
|
|
568
|
-
|
|
658
|
+
@jobs.each(now) do |job|
|
|
569
659
|
|
|
570
|
-
|
|
571
|
-
end
|
|
660
|
+
job.trigger(now)
|
|
572
661
|
end
|
|
662
|
+
end
|
|
573
663
|
|
|
574
|
-
|
|
664
|
+
def timeout_jobs
|
|
575
665
|
|
|
576
|
-
|
|
666
|
+
work_threads(:active).each do |t|
|
|
577
667
|
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
668
|
+
job = t[:rufus_scheduler_job]
|
|
669
|
+
to = t[:rufus_scheduler_timeout]
|
|
670
|
+
ts = t[:rufus_scheduler_time]
|
|
581
671
|
|
|
582
|
-
|
|
583
|
-
|
|
672
|
+
next unless job && to && ts
|
|
673
|
+
# thread might just have become inactive (job -> nil)
|
|
584
674
|
|
|
585
|
-
|
|
675
|
+
to = ts + to unless to.is_a?(EoTime)
|
|
586
676
|
|
|
587
|
-
|
|
677
|
+
next if to > EoTime.now
|
|
588
678
|
|
|
589
|
-
|
|
590
|
-
end
|
|
679
|
+
t.raise(Rufus::Scheduler::TimeoutError)
|
|
591
680
|
end
|
|
681
|
+
end
|
|
682
|
+
|
|
683
|
+
def rejoin
|
|
592
684
|
|
|
593
|
-
|
|
685
|
+
(@join_queue.num_waiting * 2 + 1).times { @join_queue << @thread }
|
|
686
|
+
end
|
|
594
687
|
|
|
595
|
-
|
|
596
|
-
'cannot schedule, scheduler is down or shutting down'
|
|
597
|
-
) if @started_at.nil?
|
|
688
|
+
def do_schedule(job_type, t, callable, opts, return_job_instance, block)
|
|
598
689
|
|
|
599
|
-
|
|
600
|
-
|
|
690
|
+
fail NotRunningError.new(
|
|
691
|
+
'cannot schedule, scheduler is down or shutting down'
|
|
692
|
+
) if @started_at.nil?
|
|
601
693
|
|
|
602
|
-
|
|
694
|
+
callable, opts = nil, callable if callable.is_a?(Hash)
|
|
695
|
+
opts = opts.dup unless opts.has_key?(:_t)
|
|
603
696
|
|
|
604
|
-
|
|
605
|
-
case job_type
|
|
606
|
-
when :once
|
|
607
|
-
opts[:_t] ||= Rufus::Scheduler.parse(t, opts)
|
|
608
|
-
opts[:_t].is_a?(Numeric) ? InJob : AtJob
|
|
609
|
-
when :every
|
|
610
|
-
EveryJob
|
|
611
|
-
when :interval
|
|
612
|
-
IntervalJob
|
|
613
|
-
when :cron
|
|
614
|
-
CronJob
|
|
615
|
-
end
|
|
697
|
+
return_job_instance ||= opts[:job]
|
|
616
698
|
|
|
617
|
-
|
|
618
|
-
|
|
699
|
+
job_class =
|
|
700
|
+
case job_type
|
|
701
|
+
when :once
|
|
702
|
+
opts[:_t] ||= Rufus::Scheduler.parse(t, opts)
|
|
703
|
+
opts[:_t].is_a?(Numeric) ? InJob : AtJob
|
|
704
|
+
when :every
|
|
705
|
+
EveryJob
|
|
706
|
+
when :interval
|
|
707
|
+
IntervalJob
|
|
708
|
+
when :cron
|
|
709
|
+
CronJob
|
|
710
|
+
end
|
|
619
711
|
|
|
620
|
-
|
|
712
|
+
job = job_class.new(self, t, opts, block || callable)
|
|
713
|
+
job.check_frequency
|
|
621
714
|
|
|
622
|
-
|
|
623
|
-
|
|
715
|
+
@jobs.push(job)
|
|
716
|
+
|
|
717
|
+
return_job_instance ? job : job.job_id
|
|
624
718
|
end
|
|
719
|
+
|
|
720
|
+
def monow; self.class.monow; end
|
|
721
|
+
def ltstamp; self.class.ltstamp; end
|
|
625
722
|
end
|
|
626
723
|
|