resque-scheduler 4.3.1 → 4.6.0
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.
Potentially problematic release.
This version of resque-scheduler might be problematic. Click here for more details.
- checksums.yaml +5 -5
- data/.github/dependabot.yml +12 -0
- data/.github/funding.yml +4 -0
- data/.github/workflows/codeql-analysis.yml +59 -0
- data/.github/workflows/rubocop.yml +27 -0
- data/.github/workflows/ruby.yml +66 -0
- data/AUTHORS.md +9 -0
- data/CHANGELOG.md +49 -2
- data/Gemfile +14 -0
- data/README.md +102 -24
- data/Rakefile +2 -5
- data/lib/resque/scheduler/configuration.rb +31 -8
- data/lib/resque/scheduler/delaying_extensions.rb +65 -18
- data/lib/resque/scheduler/env.rb +3 -7
- data/lib/resque/scheduler/lock/resilient.rb +2 -2
- data/lib/resque/scheduler/locking.rb +3 -3
- data/lib/resque/scheduler/scheduling_extensions.rb +4 -3
- data/lib/resque/scheduler/server/views/delayed.erb +4 -4
- data/lib/resque/scheduler/server/views/delayed_timestamp.erb +1 -1
- data/lib/resque/scheduler/server/views/scheduler.erb +2 -2
- data/lib/resque/scheduler/server/views/search.erb +0 -3
- data/lib/resque/scheduler/server/views/search_form.erb +1 -5
- data/lib/resque/scheduler/server.rb +1 -1
- data/lib/resque/scheduler/signal_handling.rb +2 -2
- data/lib/resque/scheduler/util.rb +1 -1
- data/lib/resque/scheduler/version.rb +1 -1
- data/lib/resque/scheduler.rb +27 -15
- data/resque-scheduler.gemspec +14 -8
- metadata +25 -32
@@ -24,7 +24,7 @@ module Resque
|
|
24
24
|
def enqueue_at_with_queue(queue, timestamp, klass, *args)
|
25
25
|
return false unless plugin.run_before_schedule_hooks(klass, *args)
|
26
26
|
|
27
|
-
if Resque.inline? || timestamp.to_i
|
27
|
+
if Resque.inline? || timestamp.to_i <= Time.now.to_i
|
28
28
|
# Just create the job and let resque perform it right away with
|
29
29
|
# inline. If the class is a custom job class, call self#scheduled
|
30
30
|
# on it. This allows you to do things like
|
@@ -33,7 +33,7 @@ module Resque
|
|
33
33
|
if klass.respond_to?(:scheduled)
|
34
34
|
klass.scheduled(queue, klass.to_s, *args)
|
35
35
|
else
|
36
|
-
Resque
|
36
|
+
Resque.enqueue_to(queue, klass, *args)
|
37
37
|
end
|
38
38
|
else
|
39
39
|
delayed_push(timestamp, job_to_hash_with_queue(queue, klass, args))
|
@@ -45,6 +45,9 @@ module Resque
|
|
45
45
|
# Identical to enqueue_at but takes number_of_seconds_from_now
|
46
46
|
# instead of a timestamp.
|
47
47
|
def enqueue_in(number_of_seconds_from_now, klass, *args)
|
48
|
+
unless number_of_seconds_from_now.is_a?(Numeric)
|
49
|
+
raise ArgumentError, 'Please supply a numeric number of seconds'
|
50
|
+
end
|
48
51
|
enqueue_at(Time.now + number_of_seconds_from_now, klass, *args)
|
49
52
|
end
|
50
53
|
|
@@ -53,14 +56,35 @@ module Resque
|
|
53
56
|
# number of seconds has passed.
|
54
57
|
def enqueue_in_with_queue(queue, number_of_seconds_from_now,
|
55
58
|
klass, *args)
|
59
|
+
unless number_of_seconds_from_now.is_a?(Numeric)
|
60
|
+
raise ArgumentError, 'Please supply a numeric number of seconds'
|
61
|
+
end
|
56
62
|
enqueue_at_with_queue(queue, Time.now + number_of_seconds_from_now,
|
57
63
|
klass, *args)
|
58
64
|
end
|
59
65
|
|
66
|
+
# Update the delayed timestamp of any matching delayed jobs or enqueue a
|
67
|
+
# new job if no matching jobs are found. Returns the number of delayed or
|
68
|
+
# enqueued jobs.
|
69
|
+
def delay_or_enqueue_at(timestamp, klass, *args)
|
70
|
+
count = remove_delayed(klass, *args)
|
71
|
+
count = 1 if count == 0
|
72
|
+
|
73
|
+
count.times do
|
74
|
+
enqueue_at(timestamp, klass, *args)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
# Identical to +delay_or_enqueue_at+, except it takes
|
79
|
+
# number_of_seconds_from_now instead of a timestamp
|
80
|
+
def delay_or_enqueue_in(number_of_seconds_from_now, klass, *args)
|
81
|
+
delay_or_enqueue_at(Time.now + number_of_seconds_from_now, klass, *args)
|
82
|
+
end
|
83
|
+
|
60
84
|
# Used internally to stuff the item into the schedule sorted list.
|
61
|
-
# +timestamp+ can be either in seconds or a datetime object
|
62
|
-
#
|
63
|
-
# that time, else false
|
85
|
+
# +timestamp+ can be either in seconds or a datetime object. The
|
86
|
+
# insertion time complexity is O(log(n)). Returns true if it's
|
87
|
+
# the first job to be scheduled at that time, else false.
|
64
88
|
def delayed_push(timestamp, item)
|
65
89
|
# First add this item to the list for this timestamp
|
66
90
|
redis.rpush("delayed:#{timestamp.to_i}", encode(item))
|
@@ -82,6 +106,7 @@ module Resque
|
|
82
106
|
end
|
83
107
|
|
84
108
|
# Returns the size of the delayed queue schedule
|
109
|
+
# this does not represent the number of items in the queue to be scheduled
|
85
110
|
def delayed_queue_schedule_size
|
86
111
|
redis.zcard :delayed_queue_schedule
|
87
112
|
end
|
@@ -128,10 +153,7 @@ module Resque
|
|
128
153
|
Array(redis.zrange(:delayed_queue_schedule, 0, -1)).each do |item|
|
129
154
|
key = "delayed:#{item}"
|
130
155
|
items = redis.lrange(key, 0, -1)
|
131
|
-
redis.
|
132
|
-
items.each { |ts_item| redis.del("timestamps:#{ts_item}") }
|
133
|
-
end
|
134
|
-
redis.del key
|
156
|
+
redis.del(key, items.map { |ts_item| "timestamps:#{ts_item}" })
|
135
157
|
end
|
136
158
|
|
137
159
|
redis.del :delayed_queue_schedule
|
@@ -143,6 +165,11 @@ module Resque
|
|
143
165
|
remove_delayed_job(search)
|
144
166
|
end
|
145
167
|
|
168
|
+
def remove_delayed_in_queue(klass, queue, *args)
|
169
|
+
search = encode(job_to_hash_with_queue(queue, klass, args))
|
170
|
+
remove_delayed_job(search)
|
171
|
+
end
|
172
|
+
|
146
173
|
# Given an encoded item, enqueue it now
|
147
174
|
def enqueue_delayed(klass, *args)
|
148
175
|
hash = job_to_hash(klass, args)
|
@@ -151,6 +178,13 @@ module Resque
|
|
151
178
|
end
|
152
179
|
end
|
153
180
|
|
181
|
+
def enqueue_delayed_with_queue(klass, queue, *args)
|
182
|
+
hash = job_to_hash_with_queue(queue, klass, args)
|
183
|
+
remove_delayed_in_queue(klass, queue, *args).times do
|
184
|
+
Resque::Scheduler.enqueue_from_config(hash)
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
154
188
|
# Given a block, remove jobs that return true from a block
|
155
189
|
#
|
156
190
|
# This allows for removal of delayed jobs that have arguments matching
|
@@ -175,7 +209,15 @@ module Resque
|
|
175
209
|
found_jobs.reduce(0) do |sum, encoded_job|
|
176
210
|
decoded_job = decode(encoded_job)
|
177
211
|
klass = Util.constantize(decoded_job['class'])
|
178
|
-
|
212
|
+
queue = decoded_job['queue']
|
213
|
+
|
214
|
+
if queue
|
215
|
+
jobs_queued = enqueue_delayed_with_queue(klass, queue, *decoded_job['args'])
|
216
|
+
else
|
217
|
+
jobs_queued = enqueue_delayed(klass, *decoded_job['args'])
|
218
|
+
end
|
219
|
+
|
220
|
+
jobs_queued + sum
|
179
221
|
end
|
180
222
|
end
|
181
223
|
|
@@ -190,9 +232,9 @@ module Resque
|
|
190
232
|
|
191
233
|
# Beyond 100 there's almost no improvement in speed
|
192
234
|
found = timestamps.each_slice(100).map do |ts_group|
|
193
|
-
jobs = redis.pipelined do |
|
235
|
+
jobs = redis.pipelined do |pipeline|
|
194
236
|
ts_group.each do |ts|
|
195
|
-
|
237
|
+
pipeline.lrange("delayed:#{ts}", 0, -1)
|
196
238
|
end
|
197
239
|
end
|
198
240
|
|
@@ -265,18 +307,23 @@ module Resque
|
|
265
307
|
{ class: klass.to_s, args: args, queue: queue }
|
266
308
|
end
|
267
309
|
|
310
|
+
# Removes a job from the queue, but not modify the timestamp schedule. This method
|
311
|
+
# will not effect the output of `delayed_queue_schedule_size`
|
268
312
|
def remove_delayed_job(encoded_job)
|
269
313
|
return 0 if Resque.inline?
|
270
314
|
|
271
315
|
timestamps = redis.smembers("timestamps:#{encoded_job}")
|
272
316
|
|
273
|
-
replies = redis.pipelined do
|
317
|
+
replies = redis.pipelined do |pipeline|
|
274
318
|
timestamps.each do |key|
|
275
|
-
|
276
|
-
|
319
|
+
pipeline.lrem(key, 0, encoded_job)
|
320
|
+
pipeline.srem("timestamps:#{encoded_job}", key)
|
277
321
|
end
|
278
322
|
end
|
279
323
|
|
324
|
+
# timestamp key is not removed from the schedule, this is done later
|
325
|
+
# by the scheduler loop
|
326
|
+
|
280
327
|
return 0 if replies.nil? || replies.empty?
|
281
328
|
replies.each_slice(2).map(&:first).inject(:+)
|
282
329
|
end
|
@@ -287,9 +334,9 @@ module Resque
|
|
287
334
|
redis.watch(key) do
|
288
335
|
if redis.llen(key).to_i == 0
|
289
336
|
# If the list is empty, remove it.
|
290
|
-
redis.multi do
|
291
|
-
|
292
|
-
|
337
|
+
redis.multi do |transaction|
|
338
|
+
transaction.del(key)
|
339
|
+
transaction.zrem(:delayed_queue_schedule, timestamp.to_i)
|
293
340
|
end
|
294
341
|
else
|
295
342
|
redis.redis.unwatch
|
data/lib/resque/scheduler/env.rb
CHANGED
@@ -38,12 +38,8 @@ module Resque
|
|
38
38
|
true
|
39
39
|
end
|
40
40
|
|
41
|
-
unless Process.respond_to?('daemon')
|
42
|
-
abort 'background option is set, which requires ruby >= 1.9'
|
43
|
-
end
|
44
|
-
|
45
41
|
Process.daemon(true, !Resque::Scheduler.quiet)
|
46
|
-
Resque.redis.
|
42
|
+
Resque.redis._client.reconnect
|
47
43
|
end
|
48
44
|
|
49
45
|
def setup_pid_file
|
@@ -64,13 +60,13 @@ module Resque
|
|
64
60
|
|
65
61
|
c.dynamic = !!options[:dynamic] if options.key?(:dynamic)
|
66
62
|
|
67
|
-
c.env = options[:env] if options.key(:env)
|
63
|
+
c.env = options[:env] if options.key?(:env)
|
68
64
|
|
69
65
|
c.logfile = options[:logfile] if options.key?(:logfile)
|
70
66
|
|
71
67
|
c.logformat = options[:logformat] if options.key?(:logformat)
|
72
68
|
|
73
|
-
if psleep = options[:poll_sleep_amount] && !psleep.nil?
|
69
|
+
if (psleep = options[:poll_sleep_amount]) && !psleep.nil?
|
74
70
|
c.poll_sleep_amount = Float(psleep)
|
75
71
|
end
|
76
72
|
|
@@ -43,7 +43,7 @@ module Resque
|
|
43
43
|
@locked_sha = nil if refresh
|
44
44
|
|
45
45
|
@locked_sha ||=
|
46
|
-
Resque.redis.script(:load, <<-EOF.gsub(/^ {14}/, ''))
|
46
|
+
Resque.data_store.redis.script(:load, <<-EOF.gsub(/^ {14}/, ''))
|
47
47
|
if redis.call('GET', KEYS[1]) == ARGV[1]
|
48
48
|
then
|
49
49
|
redis.call('EXPIRE', KEYS[1], #{timeout})
|
@@ -62,7 +62,7 @@ module Resque
|
|
62
62
|
@acquire_sha = nil if refresh
|
63
63
|
|
64
64
|
@acquire_sha ||=
|
65
|
-
Resque.redis.script(:load, <<-EOF.gsub(/^ {14}/, ''))
|
65
|
+
Resque.data_store.redis.script(:load, <<-EOF.gsub(/^ {14}/, ''))
|
66
66
|
if redis.call('SETNX', KEYS[1], ARGV[1]) == 1
|
67
67
|
then
|
68
68
|
redis.call('EXPIRE', KEYS[1], #{timeout})
|
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
# ### Locking the scheduler process
|
4
4
|
#
|
5
|
-
# There are two places in resque-scheduler that need to be
|
5
|
+
# There are two places in resque-scheduler that need to be synchronized in order
|
6
6
|
# to be able to run redundant scheduler processes while ensuring jobs don't get
|
7
7
|
# queued multiple times when the master process changes.
|
8
8
|
#
|
@@ -76,7 +76,7 @@ module Resque
|
|
76
76
|
|
77
77
|
def release_master_lock
|
78
78
|
master_lock.release
|
79
|
-
rescue
|
79
|
+
rescue *INTERMITTENT_ERRORS
|
80
80
|
@master_lock = nil
|
81
81
|
end
|
82
82
|
|
@@ -97,7 +97,7 @@ module Resque
|
|
97
97
|
end
|
98
98
|
|
99
99
|
def redis_master_version
|
100
|
-
Resque.redis.info['redis_version'].to_f
|
100
|
+
Resque.data_store.redis.info['redis_version'].to_f
|
101
101
|
end
|
102
102
|
end
|
103
103
|
end
|
@@ -36,7 +36,7 @@ module Resque
|
|
36
36
|
# :args can be any yaml which will be converted to a ruby literal and
|
37
37
|
# passed in a params. (optional)
|
38
38
|
#
|
39
|
-
# :
|
39
|
+
# :rails_env is the list of envs where the job gets loaded. Envs are
|
40
40
|
# comma separated (optional)
|
41
41
|
#
|
42
42
|
# :description is just that, a description of the job (optional). If
|
@@ -101,12 +101,13 @@ module Resque
|
|
101
101
|
end
|
102
102
|
|
103
103
|
# remove a given schedule by name
|
104
|
-
|
104
|
+
# Preventing a reload is optional and available to batch operations
|
105
|
+
def remove_schedule(name, reload = true)
|
105
106
|
non_persistent_schedules.delete(name)
|
106
107
|
redis.hdel(:persistent_schedules, name)
|
107
108
|
redis.sadd(:schedules_changed, name)
|
108
109
|
|
109
|
-
reload_schedule!
|
110
|
+
reload_schedule! if reload
|
110
111
|
end
|
111
112
|
|
112
113
|
private
|
@@ -1,9 +1,9 @@
|
|
1
1
|
<h1>Delayed Jobs</h1>
|
2
|
-
|
2
|
+
<% size = resque.delayed_queue_schedule_size %>
|
3
3
|
|
4
4
|
<%= scheduler_view :search_form, layout: false %>
|
5
5
|
|
6
|
-
<p style="
|
6
|
+
<p style="color: red; font-weight: bold;">
|
7
7
|
<%= @error_message %>
|
8
8
|
</p>
|
9
9
|
|
@@ -46,7 +46,7 @@
|
|
46
46
|
<td><%= h(show_job_arguments(job['args'])) if job && delayed_timestamp_size == 1 %></td>
|
47
47
|
<td>
|
48
48
|
<% if job %>
|
49
|
-
<a href="<%=u URI("/delayed/jobs/#{job['class']}?args=" +
|
49
|
+
<a href="<%= u URI("/delayed/jobs/#{CGI.escape(job['class'])}?args=" + CGI.escape(job['args'].to_json)) %>">All schedules</a>
|
50
50
|
<% end %>
|
51
51
|
</td>
|
52
52
|
</tr>
|
@@ -55,7 +55,7 @@
|
|
55
55
|
|
56
56
|
<% if size > 0 %>
|
57
57
|
<br>
|
58
|
-
<form method="POST" action="<%=u 'delayed/clear'%>" class='clear-delayed'>
|
58
|
+
<form method="POST" action="<%= u 'delayed/clear' %>" class='clear-delayed'>
|
59
59
|
<input type='submit' name='' value='Clear Delayed Jobs' />
|
60
60
|
</form>
|
61
61
|
<% end %>
|
@@ -8,7 +8,7 @@
|
|
8
8
|
<br/> Current master: <%= Resque.redis.get(Resque::Scheduler.master_lock.key) %>
|
9
9
|
</p>
|
10
10
|
<p class='intro'>
|
11
|
-
|
11
|
+
The highlighted jobs are skipped for current environment.
|
12
12
|
</p>
|
13
13
|
<div style="overflow-y: auto; width:100%; padding: 0px 5px;">
|
14
14
|
<table>
|
@@ -29,7 +29,7 @@
|
|
29
29
|
<% Resque.schedule.keys.sort.each_with_index do |name, index| %>
|
30
30
|
<% config = Resque.schedule[name] %>
|
31
31
|
<tr style="<%= scheduled_in_this_env?(name) ? '' : 'color: #9F6000;background: #FEEFB3;' %>">
|
32
|
-
|
32
|
+
<td style="padding-left: 15px;"><%= index + 1 %>.</td>
|
33
33
|
<% if Resque::Scheduler.dynamic %>
|
34
34
|
<td style="padding-top: 12px; padding-bottom: 2px; width: 10px">
|
35
35
|
<form action="<%= u "/schedule" %>" method="post" style="margin-left: 0">
|
@@ -87,7 +87,7 @@ module Resque
|
|
87
87
|
def delayed_jobs_klass
|
88
88
|
begin
|
89
89
|
klass = Resque::Scheduler::Util.constantize(params[:klass])
|
90
|
-
@args = JSON.load(
|
90
|
+
@args = JSON.load(CGI.unescape(params[:args]))
|
91
91
|
@timestamps = Resque.scheduled_at(klass, *@args)
|
92
92
|
rescue
|
93
93
|
@timestamps = []
|
@@ -10,13 +10,13 @@ module Resque
|
|
10
10
|
end
|
11
11
|
|
12
12
|
# For all signals, set the shutdown flag and wait for current
|
13
|
-
# poll/
|
13
|
+
# poll/enqueuing to finish (should be almost instant). In the
|
14
14
|
# case of sleeping, exit immediately.
|
15
15
|
def register_signal_handlers
|
16
16
|
(Signal.list.keys & %w(INT TERM USR1 USR2 QUIT)).each do |sig|
|
17
17
|
trap(sig) do
|
18
18
|
signal_queue << sig
|
19
|
-
# break sleep in the primary scheduler thread,
|
19
|
+
# break sleep in the primary scheduler thread, allowing
|
20
20
|
# the signal queue to get processed as soon as possible.
|
21
21
|
@th.wakeup if @th && @th.alive?
|
22
22
|
end
|
@@ -4,7 +4,7 @@ module Resque
|
|
4
4
|
module Scheduler
|
5
5
|
class Util
|
6
6
|
# In order to upgrade to resque(1.25) which has deprecated following
|
7
|
-
# methods, we just added these
|
7
|
+
# methods, we just added these useful helpers back to use in Resque
|
8
8
|
# Scheduler. refer to:
|
9
9
|
# https://github.com/resque/resque-scheduler/pull/273
|
10
10
|
|
data/lib/resque/scheduler.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
# vim:fileencoding=utf-8
|
2
2
|
|
3
|
+
require 'redis/errors'
|
3
4
|
require 'rufus/scheduler'
|
4
5
|
require_relative 'scheduler/configuration'
|
5
6
|
require_relative 'scheduler/locking'
|
@@ -13,6 +14,9 @@ module Resque
|
|
13
14
|
autoload :Extension, 'resque/scheduler/extension'
|
14
15
|
autoload :Util, 'resque/scheduler/util'
|
15
16
|
autoload :VERSION, 'resque/scheduler/version'
|
17
|
+
INTERMITTENT_ERRORS = [
|
18
|
+
Errno::EAGAIN, Errno::ECONNRESET, Redis::CannotConnectError, Redis::TimeoutError
|
19
|
+
].freeze
|
16
20
|
|
17
21
|
private
|
18
22
|
|
@@ -44,13 +48,7 @@ module Resque
|
|
44
48
|
$stdout.sync = true
|
45
49
|
$stderr.sync = true
|
46
50
|
|
47
|
-
|
48
|
-
# If dynamic is set, load that schedule otherwise use normal load
|
49
|
-
if dynamic
|
50
|
-
reload_schedule!
|
51
|
-
else
|
52
|
-
load_schedule!
|
53
|
-
end
|
51
|
+
was_master = nil
|
54
52
|
|
55
53
|
begin
|
56
54
|
@th = Thread.current
|
@@ -58,11 +56,21 @@ module Resque
|
|
58
56
|
# Now start the scheduling part of the loop.
|
59
57
|
loop do
|
60
58
|
begin
|
61
|
-
|
59
|
+
# Check on changes to master/child
|
60
|
+
@am_master = master?
|
61
|
+
if am_master != was_master
|
62
|
+
procline am_master ? 'Master scheduler' : 'Child scheduler'
|
63
|
+
|
64
|
+
# Load schedule because changed
|
65
|
+
reload_schedule!
|
66
|
+
end
|
67
|
+
|
68
|
+
if am_master
|
62
69
|
handle_delayed_items
|
63
70
|
update_schedule if dynamic
|
64
71
|
end
|
65
|
-
|
72
|
+
was_master = am_master
|
73
|
+
rescue *INTERMITTENT_ERRORS => e
|
66
74
|
log! e.message
|
67
75
|
release_master_lock
|
68
76
|
end
|
@@ -99,7 +107,7 @@ module Resque
|
|
99
107
|
Resque.schedule.each do |name, config|
|
100
108
|
load_schedule_job(name, config)
|
101
109
|
end
|
102
|
-
Resque.redis.del(:schedules_changed)
|
110
|
+
Resque.redis.del(:schedules_changed) if am_master && dynamic
|
103
111
|
procline 'Schedules Loaded'
|
104
112
|
end
|
105
113
|
|
@@ -202,7 +210,7 @@ module Resque
|
|
202
210
|
loop do
|
203
211
|
handle_shutdown do
|
204
212
|
# Continually check that it is still the master
|
205
|
-
item = enqueue_next_item(timestamp) if
|
213
|
+
item = enqueue_next_item(timestamp) if am_master
|
206
214
|
end
|
207
215
|
# continue processing until there are no more ready items in this
|
208
216
|
# timestamp
|
@@ -243,7 +251,7 @@ module Resque
|
|
243
251
|
if job_klass && job_klass != 'Resque::Job'
|
244
252
|
# The custom job class API must offer a static "scheduled" method. If
|
245
253
|
# the custom job class can not be constantized (via a requeue call
|
246
|
-
# from the web perhaps), fall back to
|
254
|
+
# from the web perhaps), fall back to enqueuing normally via
|
247
255
|
# Resque::Job.create.
|
248
256
|
begin
|
249
257
|
Resque::Scheduler::Util.constantize(job_klass).scheduled(
|
@@ -369,7 +377,6 @@ module Resque
|
|
369
377
|
|
370
378
|
def stop_rufus_scheduler
|
371
379
|
rufus_scheduler.shutdown(:wait)
|
372
|
-
rufus_scheduler.join
|
373
380
|
end
|
374
381
|
|
375
382
|
def before_shutdown
|
@@ -420,10 +427,10 @@ module Resque
|
|
420
427
|
private
|
421
428
|
|
422
429
|
def enqueue_recurring(name, config)
|
423
|
-
if
|
430
|
+
if am_master
|
424
431
|
log! "queueing #{config['class']} (#{name})"
|
425
|
-
Resque.last_enqueued_at(name, Time.now.to_s)
|
426
432
|
enqueue(config)
|
433
|
+
Resque.last_enqueued_at(name, Time.now.to_s)
|
427
434
|
end
|
428
435
|
end
|
429
436
|
|
@@ -442,6 +449,11 @@ module Resque
|
|
442
449
|
def internal_name
|
443
450
|
"resque-scheduler-#{Resque::Scheduler::VERSION}"
|
444
451
|
end
|
452
|
+
|
453
|
+
def am_master
|
454
|
+
@am_master = master? unless defined?(@am_master)
|
455
|
+
@am_master
|
456
|
+
end
|
445
457
|
end
|
446
458
|
end
|
447
459
|
end
|
data/resque-scheduler.gemspec
CHANGED
@@ -11,12 +11,14 @@ Gem::Specification.new do |spec|
|
|
11
11
|
Simon Eskildsen
|
12
12
|
Ryan Biesemeyer
|
13
13
|
Dan Buch
|
14
|
+
Michael Bianco
|
14
15
|
EOF
|
15
16
|
spec.email = %w(
|
16
17
|
bvandenbos@gmail.com
|
17
18
|
sirup@sirupsen.com
|
18
19
|
ryan@yaauie.com
|
19
20
|
dan@meatballhat.com
|
21
|
+
mike@mikebian.co
|
20
22
|
)
|
21
23
|
spec.summary = 'Light weight job scheduling on top of Resque'
|
22
24
|
spec.description = <<-DESCRIPTION
|
@@ -24,13 +26,16 @@ Gem::Specification.new do |spec|
|
|
24
26
|
Adds methods enqueue_at/enqueue_in to schedule jobs in the future.
|
25
27
|
Also supports queueing jobs on a fixed, cron-like schedule.
|
26
28
|
DESCRIPTION
|
27
|
-
spec.homepage = '
|
29
|
+
spec.homepage = 'https://github.com/resque/resque-scheduler'
|
28
30
|
spec.license = 'MIT'
|
31
|
+
spec.metadata['rubygems_mfa_required'] = 'true'
|
32
|
+
|
33
|
+
spec.required_ruby_version = '>= 2.3.0'
|
29
34
|
|
30
35
|
spec.files = `git ls-files -z`.split("\0").reject do |f|
|
31
36
|
f.match(%r{^(test|spec|features|examples|bin|tasks)/}) ||
|
32
|
-
f.match(/^(Vagrantfile|Gemfile\.lock
|
33
|
-
f.match(/^\.(rubocop|simplecov|
|
37
|
+
f.match(/^(Vagrantfile|Gemfile\.lock)/) ||
|
38
|
+
f.match(/^\.(rubocop|simplecov|vagrant|gitignore)/)
|
34
39
|
end
|
35
40
|
spec.bindir = 'exe'
|
36
41
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
@@ -38,7 +43,6 @@ Gem::Specification.new do |spec|
|
|
38
43
|
|
39
44
|
spec.add_development_dependency 'bundler'
|
40
45
|
spec.add_development_dependency 'json'
|
41
|
-
spec.add_development_dependency 'kramdown'
|
42
46
|
spec.add_development_dependency 'minitest'
|
43
47
|
spec.add_development_dependency 'mocha'
|
44
48
|
spec.add_development_dependency 'pry'
|
@@ -47,14 +51,16 @@ Gem::Specification.new do |spec|
|
|
47
51
|
spec.add_development_dependency 'simplecov'
|
48
52
|
spec.add_development_dependency 'test-unit'
|
49
53
|
spec.add_development_dependency 'yard'
|
50
|
-
spec.add_development_dependency '
|
54
|
+
spec.add_development_dependency 'timecop'
|
51
55
|
|
52
56
|
# We pin rubocop because new cops have a tendency to result in false-y
|
53
57
|
# positives for new contributors, which is not a nice experience.
|
54
58
|
spec.add_development_dependency 'rubocop', '~> 0.40.0'
|
55
59
|
|
56
60
|
spec.add_runtime_dependency 'mono_logger', '~> 1.0'
|
57
|
-
spec.add_runtime_dependency 'redis', '>= 3.3'
|
58
|
-
spec.add_runtime_dependency 'resque', '
|
59
|
-
|
61
|
+
spec.add_runtime_dependency 'redis', '>= 3.3'
|
62
|
+
spec.add_runtime_dependency 'resque', '>= 1.27'
|
63
|
+
# rufus-scheduler v3.7 causes a failure in test/multi_process_test.rb
|
64
|
+
# rufus-scheduler v3.3 is missing a to_local method which fails tests
|
65
|
+
spec.add_runtime_dependency 'rufus-scheduler', '~> 3.2', '!= 3.3'
|
60
66
|
end
|