qless 0.9.3 → 0.10.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.
- 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
|