jobba 1.4.0 → 1.5.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: f4e9d94c44e106165f0d2ac0e0cfc45999e491e9
4
- data.tar.gz: 6f6d8db0eb8b7cbc17a9825e55b9a35365b8c4a8
3
+ metadata.gz: cb1d6250e365236cfdbe87245b5ccd520809fe5a
4
+ data.tar.gz: 24e9272312ad529d7ec0e33c4d21e8f06c4836b5
5
5
  SHA512:
6
- metadata.gz: 787771b8aaaf606437ee72425667dce7caa899ef95d965d2703710422bd50274c67a4f40992ae9306da4ead581878fe4380c6e5fb1cb2ae42cedf7d71782106b
7
- data.tar.gz: 6bb44328f4be0c0230e0760071fa1dd28a15f611c20ffb7724402674e6237d8813ff20b6ddd46d147ac4826242aa9cf0fb40727ec93a323ae72b3d181ffdf53c
6
+ metadata.gz: 26f7a2a14a1de1761acec0c584bc3d3946ae23f955ba583e2a72dcd30ee3bd647cf2daa41f32b312729d8e451ed8ffbf5a3d7deaae191746f4b9f54bc106e0ab
7
+ data.tar.gz: ff3d42902f0094392848149d37379739c87b72a4cacd77f1e3e84343855defbd574b9dc8a1b9c3c2deefe08c0b150f776dc832228f8981edd6614a8aab52d366
data/README.md CHANGED
@@ -127,7 +127,7 @@ The order of states is not enforced, and you do not have to use all states. How
127
127
 
128
128
  Generally-speaking, you should only enter any state once. Jobba only records the timestamp the first time you enter a state.
129
129
 
130
- The expection to this rule is that if call `started!` a second time, Jobba will note this as a restart. The current values in the status will be archived and your status will look like a `started` status, with the exception that the `attempt` count will be incremented. A restarted status can then enter `succeeded`, `failed`, or `killed` states and those timestamps will be stored. `job_name` and `job_args` survive the restart.
130
+ The exception to this rule is that if call `started!` a second time, Jobba will note this as a restart. The current values in the status will be archived and your status will look like a `started` status, with the exception that the `attempt` count will be incremented. A restarted status can then enter `succeeded`, `failed`, or `killed` states and those timestamps will be stored. `job_name`, `job_args` and `provider_job_id` survive the restart.
131
131
 
132
132
  The `attempt` field is zero-indexed, so the first attempt is attempt `0`.
133
133
 
@@ -171,7 +171,7 @@ my_status.save("some string")
171
171
 
172
172
  Note that if you `save` or `add_error` contains a hash with symbol keys, those keys will be converted to strings. In fact, any argument passed in to these methods will be converted to JSON and parsed back again so that the `data` and `errors` attributes returns the same thing regardless of if they are retrieved immediately after being set or after being loaded from Redis.
173
173
 
174
- ## Setting Job Name and Arguments
174
+ ## Setting Job Name, Arguments and Provider Job ID
175
175
 
176
176
  If you want to be able to query for all statuses for a certain kind of job, you can set the job's name in the status:
177
177
 
@@ -191,6 +191,12 @@ You probably will only want to track complex arguments, e.g. models in your appl
191
191
 
192
192
  Note that you can set job args with names that are either symbols or strings, but you can only read the args back by the string form of their name, e.g.
193
193
 
194
+ If you want to be able to query for the status for a specific job record or to find the job record associated with a status, you can set the job's provider_job_id in the status:
195
+
196
+ ```ruby
197
+ my_status.set_provider_job_id(42)
198
+ ```
199
+
194
200
  ```ruby
195
201
  my_status.set_job_args(foo: "bar")
196
202
  my_status.job_args['foo'] # => "bar"
@@ -333,7 +339,7 @@ Jobba.where(job_name: ["MySpecialBackgroundJob", "MyOtherJob"])
333
339
 
334
340
  **Job Arguments**
335
341
 
336
- (requires having called the optional `add_job_arg` method)
342
+ (requires having called the optional `set_job_args` method)
337
343
 
338
344
  ```ruby
339
345
  Jobba.where(job_arg: "gid://app/MyModel/42")
data/lib/jobba.rb CHANGED
@@ -20,7 +20,7 @@ module Jobba
20
20
  class << self
21
21
  extend Forwardable
22
22
 
23
- def_delegators Jobba::Status, :all, :where, :create, :create!, :find, :find!
23
+ def_delegators Jobba::Status, :all, :where, :find_by, :create, :create!, :find, :find!
24
24
  end
25
25
 
26
26
  def self.configure
data/lib/jobba/clause.rb CHANGED
@@ -6,18 +6,18 @@ class Jobba::Clause
6
6
  # if `keys` or `suffixes` is an array, all entries will be included in the resulting set
7
7
  def initialize(prefix: nil, suffixes: nil, keys: nil, min: nil, max: nil)
8
8
  if keys.nil? && prefix.nil? && suffixes.nil?
9
- raise ArgumentError, "Either `keys` or both `prefix` and `suffix` must be specified."
9
+ raise ArgumentError, "Either `keys` or both `prefix` and `suffix` must be specified.", caller
10
10
  end
11
11
 
12
12
  if (prefix.nil? && !suffixes.nil?) || (!prefix.nil? && suffixes.nil?)
13
- raise ArgumentError, "When `prefix` is given, so must `suffix` be, and vice versa."
13
+ raise ArgumentError, "When `prefix` is given, so must `suffix` be, and vice versa.", caller
14
14
  end
15
15
 
16
16
  if keys
17
17
  @keys = [keys].flatten
18
18
  else
19
19
  prefix = "#{prefix}:" unless prefix[-1] == ":"
20
- @keys = [suffixes].flatten.collect{|suffix| prefix + suffix}
20
+ @keys = [suffixes].flatten.collect{|suffix| "#{prefix}#{suffix}"}
21
21
  end
22
22
 
23
23
  @min = min
@@ -5,7 +5,7 @@ class Jobba::ClauseFactory
5
5
  def self.new_clause(key, value)
6
6
  if value.nil?
7
7
  raise ArgumentError, "Nil search criteria are not currently " \
8
- "accepted in a Jobba `where` call"
8
+ "accepted in a Jobba `where` call", caller
9
9
  end
10
10
 
11
11
  case key.to_sym
@@ -15,12 +15,14 @@ class Jobba::ClauseFactory
15
15
  Jobba::Clause.new(prefix: "job_name", suffixes: value)
16
16
  when :job_arg
17
17
  Jobba::Clause.new(prefix: "job_arg", suffixes: value)
18
+ when :provider_job_id
19
+ Jobba::Clause.new(prefix: "provider_job_id", suffixes: value)
18
20
  when :id
19
21
  Jobba::IdClause.new(value)
20
22
  when /.*_at/
21
23
  timestamp_clause(key, value)
22
24
  else
23
- raise ArgumentError, "#{key} is not a valid key in a Jobba `where` call"
25
+ raise ArgumentError, "#{key} is not a valid key in a Jobba `where` call", caller
24
26
  end
25
27
  end
26
28
 
@@ -31,7 +33,7 @@ class Jobba::ClauseFactory
31
33
  case options
32
34
  when Array
33
35
  if options.length != 2
34
- raise ArgumentError, "Wrong number of array entries for '#{timestamp_name}'."
36
+ raise ArgumentError, "Wrong number of array entries for '#{timestamp_name}'.", caller
35
37
  end
36
38
 
37
39
  [options[0], options[1]]
@@ -40,7 +42,8 @@ class Jobba::ClauseFactory
40
42
  else
41
43
  raise ArgumentError,
42
44
  "#{option_value} is not a valid value for a " +
43
- "#{option_key} key in a Jobba `where` call"
45
+ "#{option_key} key in a Jobba `where` call",
46
+ caller
44
47
  end
45
48
 
46
49
  min = Jobba::Utils.time_to_usec_int(min)
@@ -68,14 +71,14 @@ class Jobba::ClauseFactory
68
71
  def self.validate_state_name!(state_name)
69
72
  [state_name].flatten.each do |name|
70
73
  if Jobba::State::ALL.none?{|state| state.name == name.to_s}
71
- raise ArgumentError, "'#{name}' is not a valid state name."
74
+ raise ArgumentError, "'#{name}' is not a valid state name.", caller
72
75
  end
73
76
  end
74
77
  end
75
78
 
76
79
  def self.validate_timestamp_name!(timestamp_name)
77
80
  if Jobba::State::ALL.none?{|state| state.timestamp_name == timestamp_name.to_s}
78
- raise ArgumentError, "'#{timestamp_name}' is not a valid timestamp."
81
+ raise ArgumentError, "'#{timestamp_name}' is not a valid timestamp.", caller
79
82
  end
80
83
  end
81
84
 
data/lib/jobba/status.rb CHANGED
@@ -14,6 +14,10 @@ module Jobba
14
14
  all.where(*args)
15
15
  end
16
16
 
17
+ def self.find_by(*args)
18
+ all.where(*args).first
19
+ end
20
+
17
21
  def self.create!
18
22
  create(state: State::UNQUEUED)
19
23
  end
@@ -36,8 +40,9 @@ module Jobba
36
40
  end
37
41
 
38
42
  def self.local_attrs
39
- %w(id state progress errors data kill_requested_at job_name job_args attempt) +
40
- State::ALL.collect(&:timestamp_name)
43
+ %w(id state progress errors data kill_requested_at
44
+ job_name job_args provider_job_id attempt prior_attempts) +
45
+ State::ALL.collect(&:timestamp_name)
41
46
  end
42
47
 
43
48
  def reload!
@@ -111,7 +116,8 @@ module Jobba
111
116
  end
112
117
 
113
118
  def set_job_name(job_name)
114
- raise ArgumentError, "`job_name` must not be blank" if job_name.nil? || job_name.empty?
119
+ raise ArgumentError, "`job_name` must not be blank", caller \
120
+ if job_name.nil? || job_name.empty?
115
121
 
116
122
  redis.multi do
117
123
  redis.srem(job_name_key, id)
@@ -121,8 +127,9 @@ module Jobba
121
127
  end
122
128
 
123
129
  def set_job_args(args_hash={})
124
- raise ArgumentError, "All values in the hash passed to `set_job_args` must be strings" \
125
- if args_hash.values.any?{|val| !val.is_a?(String)}
130
+ raise ArgumentError,
131
+ "All values in the hash passed to `set_job_args` must be strings",
132
+ caller if args_hash.values.any?{|val| !val.is_a?(String)}
126
133
 
127
134
  args_hash = normalize_for_json(args_hash)
128
135
 
@@ -133,8 +140,19 @@ module Jobba
133
140
  end
134
141
  end
135
142
 
143
+ def set_provider_job_id(provider_job_id)
144
+ raise ArgumentError, "`provider_job_id` must not be blank", caller \
145
+ if provider_job_id.nil? || (provider_job_id.respond_to?(:empty?) && provider_job_id.empty?)
146
+
147
+ redis.multi do
148
+ redis.srem(provider_job_id_key, id)
149
+ set(provider_job_id: provider_job_id)
150
+ redis.sadd(provider_job_id_key, id)
151
+ end
152
+ end
153
+
136
154
  def add_error(error)
137
- raise ArgumentError, "The argument to `add_error` cannot be nil" if error.nil?
155
+ raise ArgumentError, "The argument to `add_error` cannot be nil", caller if error.nil?
138
156
 
139
157
  errors.push(normalize_for_json(error))
140
158
  set(errors: errors)
@@ -162,7 +180,7 @@ module Jobba
162
180
  end
163
181
 
164
182
  def prior_attempts
165
- [*0..attempt-1].collect{|ii| self.class.find!("#{id}:#{ii}")}
183
+ @prior_attempts ||= [*0..attempt-1].collect{|ii| self.class.find!("#{id}:#{ii}")}
166
184
  end
167
185
 
168
186
  protected
@@ -188,7 +206,8 @@ module Jobba
188
206
  progress: 0,
189
207
  errors: [],
190
208
  job_name: job_name,
191
- job_args: job_args
209
+ job_args: job_args,
210
+ provider_job_id: provider_job_id
192
211
  }
193
212
 
194
213
  archive_attempt!
@@ -223,6 +242,7 @@ module Jobba
223
242
  @attempt = attrs[:attempt] || 0
224
243
  @job_args = attrs[:job_args] || {}
225
244
  @job_name = attrs[:job_name]
245
+ @provider_job_id = attrs[:provider_job_id]
226
246
 
227
247
  if attrs[:persist]
228
248
  redis.multi do
@@ -316,9 +336,12 @@ module Jobba
316
336
  redis.srem(job_name_key, id)
317
337
 
318
338
  delete_self_from_job_args_set!
339
+
340
+ redis.srem(provider_job_id_key, id)
319
341
  end
320
342
 
321
343
  prior_attempts.each(&:delete!)
344
+ @prior_attempts = nil
322
345
  end
323
346
 
324
347
  def delete_locally!
@@ -351,7 +374,7 @@ module Jobba
351
374
  end
352
375
 
353
376
  def self.job_key(id, attempt=nil)
354
- raise(ArgumentError, "`id` cannot be nil") if id.nil?
377
+ raise ArgumentError, "`id` cannot be nil", caller if id.nil?
355
378
  attempt.nil? ? "id:#{id}" : "id:#{id}:#{attempt}"
356
379
  end
357
380
 
@@ -359,20 +382,26 @@ module Jobba
359
382
  "job_arg:#{arg}"
360
383
  end
361
384
 
385
+ def provider_job_id_key
386
+ "provider_job_id:#{provider_job_id}"
387
+ end
388
+
362
389
  def job_errors_key(id)
363
- raise(ArgumentError, "`id` cannot be nil") if id.nil?
390
+ raise ArgumentError, "`id` cannot be nil", caller if id.nil?
364
391
  "#{id}:errors"
365
392
  end
366
393
 
367
394
  def compute_fractional_progress(at, out_of)
368
395
  if at.nil?
369
- raise ArgumentError, "Must specify at least `at` argument to `progress` call"
396
+ raise ArgumentError, "Must specify at least `at` argument to `progress` call", caller
370
397
  elsif at < 0
371
- raise ArgumentError, "progress cannot be negative (at=#{at})"
398
+ raise ArgumentError, "progress cannot be negative (at=#{at})", caller
372
399
  elsif out_of && out_of < at
373
- raise ArgumentError, "`out_of` must be greater than `at` in `progress` calls"
400
+ raise ArgumentError, "`out_of` must be greater than `at` in `progress` calls", caller
374
401
  elsif out_of.nil? && (at < 0 || at > 1)
375
- raise ArgumentError, "If `out_of` not specified, `at` must be in the range [0.0, 1.0]"
402
+ raise ArgumentError,
403
+ "If `out_of` not specified, `at` must be in the range [0.0, 1.0]",
404
+ caller
376
405
  end
377
406
 
378
407
  at.to_f / (out_of || 1).to_f
@@ -11,7 +11,8 @@ class Jobba::Statuses
11
11
 
12
12
  def_delegators :@ids, :empty?
13
13
 
14
- def_delegators :load, :any?, :none?, :all?, :count, :map, :collect
14
+ def_delegators :load, :any?, :none?, :all?, :count, :length, :size,
15
+ :map, :collect, :reduce, :inject, :first, :last
15
16
 
16
17
  def select!(&block)
17
18
  modify!(:select!, &block)
@@ -25,14 +26,18 @@ class Jobba::Statuses
25
26
  if any?(&:incomplete?)
26
27
  raise(Jobba::NotCompletedError,
27
28
  "This status cannot be deleted because it isn't complete. Use " \
28
- "`delete!` if you want to delete anyway.")
29
+ "`delete_all!` if you want to delete anyway.")
29
30
  end
30
31
 
31
- delete!
32
+ delete_all!
32
33
  end
33
34
 
34
35
  def delete_all!
35
36
  load
37
+
38
+ # preload prior attempts because loading them is not `multi`-friendly
39
+ @cache.each(&:prior_attempts)
40
+
36
41
  redis.multi do
37
42
  @cache.each(&:delete!)
38
43
  end
data/lib/jobba/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Jobba
2
- VERSION = "1.4.0"
2
+ VERSION = "1.5.0"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jobba
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.4.0
4
+ version: 1.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - JP Slavinsky
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2016-01-20 00:00:00.000000000 Z
11
+ date: 2017-04-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: redis
@@ -161,7 +161,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
161
161
  version: '0'
162
162
  requirements: []
163
163
  rubyforge_project:
164
- rubygems_version: 2.4.8
164
+ rubygems_version: 2.4.5.1
165
165
  signing_key:
166
166
  specification_version: 4
167
167
  summary: Redis-based background job status tracking.