qless 0.9.3 → 0.10.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +9 -3
- data/README.md +70 -25
- data/Rakefile +125 -9
- data/exe/install_phantomjs +21 -0
- data/lib/qless.rb +115 -76
- data/lib/qless/config.rb +11 -9
- data/lib/qless/failure_formatter.rb +43 -0
- data/lib/qless/job.rb +201 -102
- data/lib/qless/job_reservers/ordered.rb +7 -1
- data/lib/qless/job_reservers/round_robin.rb +16 -6
- data/lib/qless/job_reservers/shuffled_round_robin.rb +9 -2
- data/lib/qless/lua/qless-lib.lua +2463 -0
- data/lib/qless/lua/qless.lua +2012 -0
- data/lib/qless/lua_script.rb +63 -12
- data/lib/qless/middleware/memory_usage_monitor.rb +62 -0
- data/lib/qless/middleware/metriks.rb +45 -0
- data/lib/qless/middleware/redis_reconnect.rb +6 -3
- data/lib/qless/middleware/requeue_exceptions.rb +94 -0
- data/lib/qless/middleware/retry_exceptions.rb +38 -9
- data/lib/qless/middleware/sentry.rb +3 -7
- data/lib/qless/middleware/timeout.rb +64 -0
- data/lib/qless/queue.rb +90 -55
- data/lib/qless/server.rb +177 -130
- data/lib/qless/server/views/_job.erb +33 -15
- data/lib/qless/server/views/completed.erb +11 -0
- data/lib/qless/server/views/layout.erb +70 -11
- data/lib/qless/server/views/overview.erb +93 -53
- data/lib/qless/server/views/queue.erb +9 -8
- data/lib/qless/server/views/queues.erb +18 -1
- data/lib/qless/subscriber.rb +37 -22
- data/lib/qless/tasks.rb +5 -10
- data/lib/qless/test_helpers/worker_helpers.rb +55 -0
- data/lib/qless/version.rb +3 -1
- data/lib/qless/worker.rb +4 -413
- data/lib/qless/worker/base.rb +247 -0
- data/lib/qless/worker/forking.rb +245 -0
- data/lib/qless/worker/serial.rb +41 -0
- metadata +135 -52
- data/lib/qless/qless-core/cancel.lua +0 -101
- data/lib/qless/qless-core/complete.lua +0 -233
- data/lib/qless/qless-core/config.lua +0 -56
- data/lib/qless/qless-core/depends.lua +0 -65
- data/lib/qless/qless-core/deregister_workers.lua +0 -12
- data/lib/qless/qless-core/fail.lua +0 -117
- data/lib/qless/qless-core/failed.lua +0 -83
- data/lib/qless/qless-core/get.lua +0 -37
- data/lib/qless/qless-core/heartbeat.lua +0 -51
- data/lib/qless/qless-core/jobs.lua +0 -41
- data/lib/qless/qless-core/pause.lua +0 -18
- data/lib/qless/qless-core/peek.lua +0 -165
- data/lib/qless/qless-core/pop.lua +0 -314
- data/lib/qless/qless-core/priority.lua +0 -32
- data/lib/qless/qless-core/put.lua +0 -169
- data/lib/qless/qless-core/qless-lib.lua +0 -2354
- data/lib/qless/qless-core/qless.lua +0 -1862
- data/lib/qless/qless-core/queues.lua +0 -58
- data/lib/qless/qless-core/recur.lua +0 -190
- data/lib/qless/qless-core/retry.lua +0 -73
- data/lib/qless/qless-core/stats.lua +0 -92
- data/lib/qless/qless-core/tag.lua +0 -100
- data/lib/qless/qless-core/track.lua +0 -79
- data/lib/qless/qless-core/unfail.lua +0 -54
- data/lib/qless/qless-core/unpause.lua +0 -12
- data/lib/qless/qless-core/workers.lua +0 -69
- data/lib/qless/wait_until.rb +0 -19
data/lib/qless/config.rb
CHANGED
@@ -1,4 +1,6 @@
|
|
1
|
-
|
1
|
+
# Encoding: utf-8
|
2
|
+
|
3
|
+
require 'json'
|
2
4
|
|
3
5
|
module Qless
|
4
6
|
# A configuration class associated with a qless client
|
@@ -6,24 +8,24 @@ module Qless
|
|
6
8
|
def initialize(client)
|
7
9
|
@client = client
|
8
10
|
end
|
9
|
-
|
11
|
+
|
10
12
|
def [](key)
|
11
|
-
@client.
|
13
|
+
@client.call('config.get', key)
|
12
14
|
end
|
13
|
-
|
15
|
+
|
14
16
|
def []=(key, value)
|
15
|
-
@client.
|
17
|
+
@client.call('config.set', key, value)
|
16
18
|
end
|
17
|
-
|
19
|
+
|
18
20
|
# Get the specified `qless` configuration option, or if
|
19
21
|
# none is provided, get the complete current configuration
|
20
22
|
def all
|
21
|
-
|
23
|
+
JSON.parse(@client.call('config.get'))
|
22
24
|
end
|
23
|
-
|
25
|
+
|
24
26
|
# Restore this option to the default (remove this option)
|
25
27
|
def clear(option)
|
26
|
-
@client.
|
28
|
+
@client.call('config.unset', option)
|
27
29
|
end
|
28
30
|
end
|
29
31
|
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# Encoding: utf-8
|
2
|
+
|
3
|
+
module Qless
|
4
|
+
# A helper for formatting failure messages
|
5
|
+
class FailureFormatter
|
6
|
+
Failure = Struct.new(:group, :message) do
|
7
|
+
# allow de-structring assignment
|
8
|
+
def to_ary
|
9
|
+
[group, message]
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def initialize
|
14
|
+
@replacements = { Dir.pwd => '.' }
|
15
|
+
@replacements[ENV['GEM_HOME']] = '<GEM_HOME>' if ENV.key?('GEM_HOME')
|
16
|
+
end
|
17
|
+
|
18
|
+
def format(job, error, lines_to_remove = caller(2))
|
19
|
+
group = "#{job.klass_name}:#{error.class}"
|
20
|
+
message = "#{truncated_message(error)}\n\n" +
|
21
|
+
"#{format_failure_backtrace(error.backtrace, lines_to_remove)}"
|
22
|
+
Failure.new(group, message)
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
# TODO: pull this out into a config option.
|
28
|
+
MAX_ERROR_MESSAGE_SIZE = 10_000
|
29
|
+
def truncated_message(error)
|
30
|
+
return error.message if error.message.length <= MAX_ERROR_MESSAGE_SIZE
|
31
|
+
error.message.slice(0, MAX_ERROR_MESSAGE_SIZE) +
|
32
|
+
"\n... (truncated due to length)"
|
33
|
+
end
|
34
|
+
|
35
|
+
def format_failure_backtrace(error_backtrace, lines_to_remove)
|
36
|
+
(error_backtrace - lines_to_remove).map do |line|
|
37
|
+
@replacements.reduce(line) do |formatted, (original, new)|
|
38
|
+
formatted.sub(original, new)
|
39
|
+
end
|
40
|
+
end.join("\n")
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
data/lib/qless/job.rb
CHANGED
@@ -1,9 +1,13 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
require
|
4
|
-
require
|
1
|
+
# Encoding: utf-8
|
2
|
+
|
3
|
+
require 'qless'
|
4
|
+
require 'qless/queue'
|
5
|
+
require 'qless/lua_script'
|
6
|
+
require 'redis'
|
7
|
+
require 'json'
|
5
8
|
|
6
9
|
module Qless
|
10
|
+
# The base for both Job and RecurringJob
|
7
11
|
class BaseJob
|
8
12
|
attr_reader :client
|
9
13
|
|
@@ -13,18 +17,35 @@ module Qless
|
|
13
17
|
end
|
14
18
|
|
15
19
|
def klass
|
16
|
-
@klass ||= @klass_name.split('::').
|
20
|
+
@klass ||= @klass_name.split('::').reduce(Object) do |context, name|
|
21
|
+
context.const_get(name)
|
22
|
+
end
|
17
23
|
end
|
18
24
|
|
19
25
|
def queue
|
20
26
|
@queue ||= Queue.new(@queue_name, @client)
|
21
27
|
end
|
28
|
+
|
29
|
+
def ==(other)
|
30
|
+
self.class == other.class &&
|
31
|
+
jid == other.jid &&
|
32
|
+
client == other.client
|
33
|
+
end
|
34
|
+
alias eql? ==
|
35
|
+
|
36
|
+
def hash
|
37
|
+
self.class.hash ^ jid.hash ^ client.hash
|
38
|
+
end
|
22
39
|
end
|
23
40
|
|
41
|
+
# A Qless job
|
24
42
|
class Job < BaseJob
|
25
|
-
attr_reader :jid, :expires_at, :state, :queue_name, :worker_name, :failure, :
|
43
|
+
attr_reader :jid, :expires_at, :state, :queue_name, :worker_name, :failure, :spawned_from_jid
|
44
|
+
attr_reader :klass_name, :tracked, :dependencies, :dependents
|
26
45
|
attr_reader :original_retries, :retries_left, :raw_queue_history
|
46
|
+
attr_reader :state_changed
|
27
47
|
attr_accessor :data, :priority, :tags
|
48
|
+
alias_method(:state_changed?, :state_changed)
|
28
49
|
|
29
50
|
MiddlewareMisconfiguredError = Class.new(StandardError)
|
30
51
|
|
@@ -35,14 +56,29 @@ module Qless
|
|
35
56
|
end
|
36
57
|
|
37
58
|
def perform
|
59
|
+
# If we can't find the class, we should fail the job, not try to process
|
60
|
+
begin
|
61
|
+
klass
|
62
|
+
rescue NameError
|
63
|
+
return fail("#{queue_name}-NameError", "Cannot find #{klass_name}")
|
64
|
+
end
|
65
|
+
|
66
|
+
# log a real process executing job -- before we start processing
|
67
|
+
log("started by pid:#{Process.pid}")
|
68
|
+
|
38
69
|
middlewares = Job.middlewares_on(klass)
|
39
70
|
|
40
71
|
if middlewares.last == SupportsMiddleware
|
41
72
|
klass.around_perform(self)
|
42
73
|
elsif middlewares.any?
|
43
|
-
raise MiddlewareMisconfiguredError,
|
44
|
-
|
45
|
-
|
74
|
+
raise MiddlewareMisconfiguredError, 'The middleware chain for ' +
|
75
|
+
"#{klass} (#{middlewares.inspect}) is misconfigured." +
|
76
|
+
'Qless::Job::SupportsMiddleware must be extended onto your job' +
|
77
|
+
'class first if you want to use any middleware.'
|
78
|
+
elsif !klass.respond_to?(:perform)
|
79
|
+
# If the klass doesn't have a :perform method, we should raise an error
|
80
|
+
fail("#{queue_name}-method-missing",
|
81
|
+
"#{klass_name} has no perform method")
|
46
82
|
else
|
47
83
|
klass.perform(self)
|
48
84
|
end
|
@@ -50,41 +86,46 @@ module Qless
|
|
50
86
|
|
51
87
|
def self.build(client, klass, attributes = {})
|
52
88
|
defaults = {
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
89
|
+
'jid' => Qless.generate_jid,
|
90
|
+
'spawned_from_jid' => nil,
|
91
|
+
'data' => {},
|
92
|
+
'klass' => klass.to_s,
|
93
|
+
'priority' => 0,
|
94
|
+
'tags' => [],
|
95
|
+
'worker' => 'mock_worker',
|
96
|
+
'expires' => Time.now + (60 * 60), # an hour from now
|
97
|
+
'state' => 'running',
|
98
|
+
'tracked' => false,
|
99
|
+
'queue' => 'mock_queue',
|
100
|
+
'retries' => 5,
|
101
|
+
'remaining' => 5,
|
102
|
+
'failure' => {},
|
103
|
+
'history' => [],
|
104
|
+
'dependencies' => [],
|
105
|
+
'dependents' => []
|
69
106
|
}
|
70
107
|
attributes = defaults.merge(Qless.stringify_hash_keys(attributes))
|
71
|
-
attributes[
|
108
|
+
attributes['data'] = JSON.dump(attributes['data'])
|
72
109
|
new(client, attributes)
|
73
110
|
end
|
74
111
|
|
75
112
|
def self.middlewares_on(job_klass)
|
76
|
-
job_klass.singleton_class
|
77
|
-
|
113
|
+
singleton_klass = job_klass.singleton_class
|
114
|
+
singleton_klass.ancestors.select do |ancestor|
|
115
|
+
ancestor != singleton_klass && ancestor.method_defined?(:around_perform)
|
78
116
|
end
|
79
117
|
end
|
80
118
|
|
81
119
|
def initialize(client, atts)
|
82
120
|
super(client, atts.fetch('jid'))
|
83
121
|
%w{jid data priority tags state tracked
|
84
|
-
|
85
|
-
|
122
|
+
failure dependencies dependents spawned_from_jid}.each do |att|
|
123
|
+
instance_variable_set(:"@#{att}", atts.fetch(att))
|
86
124
|
end
|
87
125
|
|
126
|
+
# Parse the data string
|
127
|
+
@data = JSON.parse(@data)
|
128
|
+
|
88
129
|
@expires_at = atts.fetch('expires')
|
89
130
|
@klass_name = atts.fetch('klass')
|
90
131
|
@queue_name = atts.fetch('queue')
|
@@ -103,9 +144,7 @@ module Qless
|
|
103
144
|
end
|
104
145
|
|
105
146
|
def priority=(priority)
|
106
|
-
if @client.
|
107
|
-
@priority = priority
|
108
|
-
end
|
147
|
+
@priority = priority if @client.call('priority', @jid, priority)
|
109
148
|
end
|
110
149
|
|
111
150
|
def [](key)
|
@@ -137,19 +176,20 @@ module Qless
|
|
137
176
|
end
|
138
177
|
|
139
178
|
def history
|
140
|
-
warn
|
141
|
-
";
|
179
|
+
warn 'WARNING: Qless::Job#history is deprecated; use' +
|
180
|
+
"Qless::Job#raw_queue_history instead; from:\n#{caller.first}"
|
142
181
|
raw_queue_history
|
143
182
|
end
|
144
183
|
|
145
184
|
def queue_history
|
146
185
|
@queue_history ||= @raw_queue_history.map do |history_event|
|
147
186
|
history_event.each_with_object({}) do |(key, value), hash|
|
148
|
-
# The only Numeric (Integer or Float) values we get in the history
|
149
|
-
|
150
|
-
|
187
|
+
# The only Numeric (Integer or Float) values we get in the history
|
188
|
+
# are timestamps
|
189
|
+
if value.is_a?(Numeric)
|
190
|
+
hash[key] = Time.at(value).utc
|
151
191
|
else
|
152
|
-
value
|
192
|
+
hash[key] = value
|
153
193
|
end
|
154
194
|
end
|
155
195
|
end
|
@@ -159,9 +199,14 @@ module Qless
|
|
159
199
|
@initially_put_at ||= history_timestamp('put', :min)
|
160
200
|
end
|
161
201
|
|
202
|
+
def spawned_from
|
203
|
+
@spawned_from ||= @client.jobs[@spawned_from_jid]
|
204
|
+
end
|
205
|
+
|
162
206
|
def to_hash
|
163
207
|
{
|
164
208
|
jid: jid,
|
209
|
+
spawned_from_jid: spawned_from_jid,
|
165
210
|
expires_at: expires_at,
|
166
211
|
state: state,
|
167
212
|
queue_name: queue_name,
|
@@ -181,108 +226,129 @@ module Qless
|
|
181
226
|
end
|
182
227
|
|
183
228
|
# Move this from it's current queue into another
|
184
|
-
def
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
229
|
+
def requeue(queue, opts = {})
|
230
|
+
queue_name = case queue
|
231
|
+
when String, Symbol then queue
|
232
|
+
else queue.name
|
233
|
+
end
|
234
|
+
|
235
|
+
note_state_change :requeue do
|
236
|
+
@client.call('requeue', @client.worker_name, queue_name, @jid, @klass_name,
|
237
|
+
JSON.dump(opts.fetch(:data, @data)),
|
238
|
+
opts.fetch(:delay, 0),
|
239
|
+
'priority', opts.fetch(:priority, @priority),
|
240
|
+
'tags', JSON.dump(opts.fetch(:tags, @tags)),
|
241
|
+
'retries', opts.fetch(:retries, @original_retries),
|
242
|
+
'depends', JSON.dump(opts.fetch(:depends, @dependencies))
|
243
|
+
)
|
189
244
|
end
|
190
245
|
end
|
246
|
+
alias move requeue # for backwards compatibility
|
247
|
+
|
248
|
+
CantFailError = Class.new(Qless::LuaScriptError)
|
191
249
|
|
192
250
|
# Fail a job
|
193
251
|
def fail(group, message)
|
194
252
|
note_state_change :fail do
|
195
|
-
@client.
|
253
|
+
@client.call(
|
254
|
+
'fail',
|
196
255
|
@jid,
|
197
256
|
@worker_name,
|
198
257
|
group, message,
|
199
|
-
|
200
|
-
JSON.generate(@data)]) || false
|
258
|
+
JSON.dump(@data)) || false
|
201
259
|
end
|
260
|
+
rescue Qless::LuaScriptError => err
|
261
|
+
raise CantFailError.new(err.message)
|
202
262
|
end
|
203
263
|
|
204
264
|
# Heartbeat a job
|
205
|
-
def heartbeat
|
206
|
-
@client.
|
265
|
+
def heartbeat
|
266
|
+
@expires_at = @client.call(
|
267
|
+
'heartbeat',
|
207
268
|
@jid,
|
208
269
|
@worker_name,
|
209
|
-
|
210
|
-
JSON.generate(@data)]) || false
|
270
|
+
JSON.dump(@data))
|
211
271
|
end
|
212
272
|
|
213
|
-
CantCompleteError = Class.new(Qless::
|
273
|
+
CantCompleteError = Class.new(Qless::LuaScriptError)
|
214
274
|
|
215
275
|
# Complete a job
|
216
276
|
# Options include
|
217
277
|
# => next (String) the next queue
|
218
278
|
# => delay (int) how long to delay it in the next queue
|
219
|
-
def complete(nxt=nil, options={})
|
279
|
+
def complete(nxt = nil, options = {})
|
220
280
|
note_state_change :complete do
|
221
|
-
|
222
|
-
@client.
|
223
|
-
@jid, @worker_name, @queue_name,
|
281
|
+
if nxt.nil?
|
282
|
+
@client.call(
|
283
|
+
'complete', @jid, @worker_name, @queue_name, JSON.dump(@data))
|
224
284
|
else
|
225
|
-
@client.
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
if response
|
231
|
-
response
|
232
|
-
else
|
233
|
-
description = if reloaded_instance = @client.jobs[@jid]
|
234
|
-
reloaded_instance.description
|
235
|
-
else
|
236
|
-
self.description + " -- can't be reloaded"
|
237
|
-
end
|
238
|
-
|
239
|
-
raise CantCompleteError, "Failed to complete #{description}"
|
285
|
+
@client.call('complete', @jid, @worker_name, @queue_name,
|
286
|
+
JSON.dump(@data), 'next', nxt, 'delay',
|
287
|
+
options.fetch(:delay, 0), 'depends',
|
288
|
+
JSON.dump(options.fetch(:depends, [])))
|
240
289
|
end
|
241
290
|
end
|
242
|
-
|
243
|
-
|
244
|
-
def state_changed?
|
245
|
-
@state_changed
|
291
|
+
rescue Qless::LuaScriptError => err
|
292
|
+
raise CantCompleteError.new(err.message)
|
246
293
|
end
|
247
294
|
|
248
295
|
def cancel
|
249
296
|
note_state_change :cancel do
|
250
|
-
@client.
|
297
|
+
@client.call('cancel', @jid)
|
251
298
|
end
|
252
299
|
end
|
253
300
|
|
254
|
-
def track
|
255
|
-
@client.
|
301
|
+
def track
|
302
|
+
@client.call('track', 'track', @jid)
|
256
303
|
end
|
257
304
|
|
258
305
|
def untrack
|
259
|
-
@client.
|
306
|
+
@client.call('track', 'untrack', @jid)
|
260
307
|
end
|
261
308
|
|
262
309
|
def tag(*tags)
|
263
|
-
@client.
|
310
|
+
@client.call('tag', 'add', @jid, *tags)
|
264
311
|
end
|
265
312
|
|
266
313
|
def untag(*tags)
|
267
|
-
@client.
|
314
|
+
@client.call('tag', 'remove', @jid, *tags)
|
268
315
|
end
|
269
316
|
|
270
|
-
def retry(delay=0)
|
317
|
+
def retry(delay = 0, group = nil, message = nil)
|
271
318
|
note_state_change :retry do
|
272
|
-
|
273
|
-
|
319
|
+
if group.nil?
|
320
|
+
results = @client.call(
|
321
|
+
'retry', @jid, @queue_name, @worker_name, delay)
|
322
|
+
results.nil? ? false : results
|
323
|
+
else
|
324
|
+
results = @client.call(
|
325
|
+
'retry', @jid, @queue_name, @worker_name, delay, group, message)
|
326
|
+
results.nil? ? false : results
|
327
|
+
end
|
274
328
|
end
|
275
329
|
end
|
276
330
|
|
277
331
|
def depend(*jids)
|
278
|
-
!!@client.
|
332
|
+
!!@client.call('depends', @jid, 'on', *jids)
|
279
333
|
end
|
280
334
|
|
281
335
|
def undepend(*jids)
|
282
|
-
!!@client.
|
336
|
+
!!@client.call('depends', @jid, 'off', *jids)
|
337
|
+
end
|
338
|
+
|
339
|
+
def timeout
|
340
|
+
@client.call('timeout', @jid)
|
283
341
|
end
|
284
342
|
|
285
|
-
|
343
|
+
def log(message, data = nil)
|
344
|
+
if data
|
345
|
+
@client.call('log', @jid, message, JSON.dump(data))
|
346
|
+
else
|
347
|
+
@client.call('log', @jid, message)
|
348
|
+
end
|
349
|
+
end
|
350
|
+
|
351
|
+
[:fail, :complete, :cancel, :requeue, :retry].each do |event|
|
286
352
|
define_method :"before_#{event}" do |&block|
|
287
353
|
@before_callbacks[event] << block
|
288
354
|
end
|
@@ -291,8 +357,8 @@ module Qless
|
|
291
357
|
@after_callbacks[event].unshift block
|
292
358
|
end
|
293
359
|
end
|
294
|
-
|
295
|
-
|
360
|
+
alias before_move before_requeue
|
361
|
+
alias after_move after_requeue
|
296
362
|
|
297
363
|
def note_state_change(event)
|
298
364
|
@before_callbacks[event].each { |blk| blk.call(self) }
|
@@ -302,65 +368,98 @@ module Qless
|
|
302
368
|
result
|
303
369
|
end
|
304
370
|
|
371
|
+
private
|
372
|
+
|
305
373
|
def history_timestamp(name, selector)
|
306
|
-
queue_history.
|
374
|
+
items = queue_history.select do |q|
|
375
|
+
q['what'] == name
|
376
|
+
end
|
377
|
+
items.map do |q|
|
378
|
+
q['when']
|
379
|
+
end.public_send(selector)
|
307
380
|
end
|
308
381
|
end
|
309
382
|
|
383
|
+
# Wraps a recurring job
|
310
384
|
class RecurringJob < BaseJob
|
311
|
-
attr_reader :jid, :data, :priority, :tags, :retries, :interval, :count
|
385
|
+
attr_reader :jid, :data, :priority, :tags, :retries, :interval, :count
|
386
|
+
attr_reader :queue_name, :klass_name, :backlog
|
312
387
|
|
313
388
|
def initialize(client, atts)
|
314
389
|
super(client, atts.fetch('jid'))
|
315
|
-
%w{jid data priority tags retries interval count}.each do |att|
|
316
|
-
|
390
|
+
%w{jid data priority tags retries interval count backlog}.each do |att|
|
391
|
+
instance_variable_set("@#{att}".to_sym, atts.fetch(att))
|
317
392
|
end
|
318
393
|
|
394
|
+
# Parse the data string
|
395
|
+
@data = JSON.parse(@data)
|
319
396
|
@klass_name = atts.fetch('klass')
|
320
397
|
@queue_name = atts.fetch('queue')
|
321
398
|
@tags = [] if @tags == {}
|
322
399
|
end
|
323
400
|
|
324
401
|
def priority=(value)
|
325
|
-
@client.
|
402
|
+
@client.call('recur.update', @jid, 'priority', value)
|
326
403
|
@priority = value
|
327
404
|
end
|
328
405
|
|
329
406
|
def retries=(value)
|
330
|
-
@client.
|
407
|
+
@client.call('recur.update', @jid, 'retries', value)
|
331
408
|
@retries = value
|
332
409
|
end
|
333
410
|
|
334
411
|
def interval=(value)
|
335
|
-
@client.
|
412
|
+
@client.call('recur.update', @jid, 'interval', value)
|
336
413
|
@interval = value
|
337
414
|
end
|
338
415
|
|
339
416
|
def data=(value)
|
340
|
-
@client.
|
417
|
+
@client.call('recur.update', @jid, 'data', JSON.dump(value))
|
341
418
|
@data = value
|
342
419
|
end
|
343
420
|
|
344
421
|
def klass=(value)
|
345
|
-
@client.
|
422
|
+
@client.call('recur.update', @jid, 'klass', value.to_s)
|
346
423
|
@klass_name = value.to_s
|
347
424
|
end
|
348
425
|
|
426
|
+
def backlog=(value)
|
427
|
+
@client.call('recur.update', @jid, 'backlog', value.to_s)
|
428
|
+
@backlog = value
|
429
|
+
end
|
430
|
+
|
349
431
|
def move(queue)
|
350
|
-
@client.
|
432
|
+
@client.call('recur.update', @jid, 'queue', queue)
|
351
433
|
@queue_name = queue
|
352
434
|
end
|
435
|
+
alias requeue move # for API parity with normal jobs
|
353
436
|
|
354
437
|
def cancel
|
355
|
-
@client.
|
438
|
+
@client.call('unrecur', @jid)
|
356
439
|
end
|
357
440
|
|
358
441
|
def tag(*tags)
|
359
|
-
@client.
|
442
|
+
@client.call('recur.tag', @jid, *tags)
|
360
443
|
end
|
361
444
|
|
362
445
|
def untag(*tags)
|
363
|
-
@client.
|
446
|
+
@client.call('recur.untag', @jid, *tags)
|
447
|
+
end
|
448
|
+
|
449
|
+
def last_spawned_jid
|
450
|
+
return nil if never_spawned?
|
451
|
+
"#{jid}-#{count}"
|
452
|
+
end
|
453
|
+
|
454
|
+
def last_spawned_job
|
455
|
+
return nil if never_spawned?
|
456
|
+
@client.jobs[last_spawned_jid]
|
457
|
+
end
|
458
|
+
|
459
|
+
private
|
460
|
+
|
461
|
+
def never_spawned?
|
462
|
+
count.zero?
|
364
463
|
end
|
365
464
|
end
|
366
465
|
end
|