dalliance 0.5.1 → 0.8.2

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.
Files changed (36) hide show
  1. checksums.yaml +5 -5
  2. data/.circleci/config.yml +107 -0
  3. data/Appraisals +10 -14
  4. data/Gemfile +1 -1
  5. data/README.rdoc +13 -1
  6. data/dalliance.gemspec +4 -4
  7. data/gemfiles/rails_5.0.gemfile +1 -1
  8. data/gemfiles/rails_5.0.gemfile.lock +116 -89
  9. data/gemfiles/rails_5.1.gemfile +1 -1
  10. data/gemfiles/rails_5.1.gemfile.lock +115 -88
  11. data/gemfiles/{rails_4.2.gemfile → rails_5.2.gemfile} +2 -2
  12. data/gemfiles/rails_5.2.gemfile.lock +209 -0
  13. data/gemfiles/{rails_4.0.gemfile → rails_6.0.gemfile} +2 -2
  14. data/gemfiles/rails_6.0.gemfile.lock +225 -0
  15. data/gemfiles/{rails_3.2.gemfile → rails_6.1.gemfile} +2 -2
  16. data/gemfiles/rails_6.1.gemfile.lock +233 -0
  17. data/lib/dalliance.rb +83 -22
  18. data/lib/dalliance/engine.rb +1 -1
  19. data/lib/dalliance/progress_meter.rb +5 -5
  20. data/lib/dalliance/version.rb +2 -2
  21. data/lib/dalliance/workers/delayed_job.rb +20 -9
  22. data/lib/dalliance/workers/resque.rb +17 -9
  23. data/spec/dalliance/asynchronous_delayed_job_spec.rb +42 -0
  24. data/spec/dalliance/asynchronous_resque_spec.rb +54 -0
  25. data/spec/dalliance/dalliance_spec.rb +2 -2
  26. data/spec/dalliance/synchronous_spec.rb +56 -1
  27. data/spec/spec_helper.rb +2 -0
  28. data/spec/support/active_record.rb +7 -1
  29. metadata +60 -21
  30. data/gemfiles/rails_3.1.gemfile +0 -12
  31. data/gemfiles/rails_3.1.gemfile.lock +0 -149
  32. data/gemfiles/rails_3.2.gemfile.lock +0 -146
  33. data/gemfiles/rails_4.0.gemfile.lock +0 -134
  34. data/gemfiles/rails_4.1.gemfile +0 -12
  35. data/gemfiles/rails_4.1.gemfile.lock +0 -140
  36. data/gemfiles/rails_4.2.gemfile.lock +0 -168
data/lib/dalliance.rb CHANGED
@@ -118,6 +118,10 @@ module Dalliance
118
118
  event :finish_dalliance do
119
119
  transition :processing => :completed
120
120
  end
121
+
122
+ event :reprocess_dalliance do
123
+ transition [:validation_error, :processing_error, :completed] => :pending
124
+ end
121
125
  end
122
126
  #END state_machine(s)
123
127
 
@@ -175,7 +179,9 @@ module Dalliance
175
179
  else
176
180
  self.class.where(id: self.id).update_all(dalliance_status: dalliance_status, dalliance_error_hash: dalliance_error_hash.to_yaml )
177
181
  end
182
+ # rubocop:disable Lint/SuppressedException
178
183
  rescue
184
+ # rubocop:enable Lint/SuppressedException
179
185
  end
180
186
  end
181
187
  end
@@ -191,7 +197,7 @@ module Dalliance
191
197
  def validate_dalliance_status
192
198
  unless error_or_completed?
193
199
  errors.add(:dalliance_status, :invalid)
194
- if defined?(Rails) && ::Rails::VERSION::MAJOR == 5 && ::Rails::VERSION::MINOR >= 0
200
+ if defined?(Rails)
195
201
  throw(:abort)
196
202
  else
197
203
  return false
@@ -213,17 +219,41 @@ module Dalliance
213
219
  end
214
220
  end
215
221
 
216
- #Force backgound_processing w/ true
217
- def dalliance_background_process(backgound_processing = nil)
218
- if backgound_processing || (backgound_processing.nil? && self.class.dalliance_options[:background_processing])
219
- self.class.dalliance_options[:worker_class].enqueue(self, processing_queue)
222
+ #Force background_processing w/ true
223
+ def dalliance_background_process(background_processing = nil)
224
+ if background_processing || (background_processing.nil? && self.class.dalliance_options[:background_processing])
225
+ self.class.dalliance_options[:worker_class].enqueue(self, processing_queue, :dalliance_process)
220
226
  else
221
227
  dalliance_process(false)
222
228
  end
223
229
  end
224
230
 
225
- #backgound_processing == false will re-raise any exceptions
226
- def dalliance_process(backgound_processing = false)
231
+ def dalliance_process(background_processing = false)
232
+ do_dalliance_process(
233
+ perform_method: self.class.dalliance_options[:dalliance_method],
234
+ background_processing: background_processing
235
+ )
236
+ end
237
+
238
+ def dalliance_background_reprocess(background_processing = nil)
239
+ # Reset state to 'pending' before queueing up
240
+ # Otherwise the model will stay on completed/processing_error until the job
241
+ # is taken by a worker, which could be a long time after this method is
242
+ # called.
243
+ reprocess_dalliance!
244
+ if background_processing || (background_processing.nil? && self.class.dalliance_options[:background_processing])
245
+ self.class.dalliance_options[:worker_class].enqueue(self, processing_queue, :do_dalliance_reprocess)
246
+ else
247
+ do_dalliance_reprocess(false)
248
+ end
249
+ end
250
+
251
+ def dalliance_reprocess(background_processing = false)
252
+ reprocess_dalliance!
253
+ do_dalliance_reprocess(background_processing)
254
+ end
255
+
256
+ def do_dalliance_process(perform_method:, background_processing: false)
227
257
  start_time = Time.now
228
258
 
229
259
  begin
@@ -233,7 +263,7 @@ module Dalliance
233
263
  build_dalliance_progress_meter(:total_count => calculate_dalliance_progress_meter_total_count).save!
234
264
  end
235
265
 
236
- self.send(self.class.dalliance_options[:dalliance_method])
266
+ self.send(perform_method)
237
267
 
238
268
  finish_dalliance! unless validation_error?
239
269
  rescue StandardError => e
@@ -255,14 +285,16 @@ module Dalliance
255
285
  else
256
286
  self.class.where(id: self.id).update_all(dalliance_status: dalliance_status, dalliance_error_hash: dalliance_error_hash.to_yaml )
257
287
  end
288
+ # rubocop:disable Lint/SuppressedException
258
289
  rescue
290
+ # rubocop:enable Lint/SuppressedException
259
291
  end
260
292
  end
261
293
 
262
294
  error_notifier.call(e)
263
295
 
264
- #Don't raise the error if we're backgound_processing...
265
- raise e unless backgound_processing && self.class.dalliance_options[:worker_class].rescue_error?
296
+ # Don't raise the error if we're background processing...
297
+ raise e unless background_processing && self.class.dalliance_options[:worker_class].rescue_error?
266
298
  ensure
267
299
  if self.class.dalliance_options[:dalliance_progress_meter] && dalliance_progress_meter
268
300
  #Works with optimistic locking...
@@ -274,8 +306,11 @@ module Dalliance
274
306
 
275
307
  dalliance_log("[dalliance] #{self.class.name}(#{id}) - #{dalliance_status} #{duration.to_i}")
276
308
 
277
- if self.class.dalliance_options[:duration_column]
278
- self.class.where(id: self.id).update_all(self.class.dalliance_options[:duration_column] => duration.to_i)
309
+ duration_column = self.class.dalliance_options[:duration_column]
310
+ if duration_column.present?
311
+ current_duration = self.send(duration_column) || 0
312
+ self.class.where(id: self.id)
313
+ .update_all(duration_column => current_duration + duration.to_f)
279
314
  end
280
315
  end
281
316
  end
@@ -305,6 +340,19 @@ module Dalliance
305
340
  end
306
341
  end
307
342
 
343
+ private
344
+
345
+ # Executes the reprocessing method defined in the model's dalliance options.
346
+ #
347
+ # @param [Boolean] background_processing
348
+ # flag if this is called from a background worker. Defaults to false.
349
+ def do_dalliance_reprocess(background_processing = false)
350
+ do_dalliance_process(
351
+ perform_method: self.class.dalliance_options[:reprocess_method],
352
+ background_processing: background_processing
353
+ )
354
+ end
355
+
308
356
  module Glue
309
357
  extend ActiveSupport::Concern
310
358
 
@@ -313,15 +361,28 @@ module Dalliance
313
361
  end
314
362
 
315
363
  module ClassMethods
316
- def dalliance(*args)
317
- options = args.last.is_a?(Hash) ? Dalliance.options.merge(args.pop) : Dalliance.options
318
-
319
- case args.length
320
- when 1
321
- options[:dalliance_method] = args[0]
322
- else
323
- raise ArgumentError, "Incorrect number of Arguements provided"
324
- end
364
+ # Enables dalliance processing for this class.
365
+ #
366
+ # @param [Symbol|String] dalliance_method
367
+ # the name of the method to call when processing the model in dalliance
368
+ # @param [Hash] options
369
+ # an optional hash of options for dalliance processing
370
+ # @option options [Symbol] :reprocess_method
371
+ # the name of the method to use to reprocess the model in dalliance
372
+ # @option options [Boolean] :dalliance_process_meter
373
+ # whether or not to display a progress meter
374
+ # @option options [String] :queue
375
+ # the name of the worker queue to use. Default 'dalliance'
376
+ # @option options [String] :duration_column
377
+ # the name of the table column that stores the dalliance processing time. Default 'dalliance_duration'
378
+ # @option options [Object] :logger
379
+ # the logger object to use. Can be nil
380
+ # @option options [Proc] :error_notifier
381
+ # A proc that accepts an error object. Default is a NOP
382
+ def dalliance(dalliance_method, options = {})
383
+ opts = Dalliance.options.merge(options)
384
+
385
+ opts[:dalliance_method] = dalliance_method
325
386
 
326
387
  if dalliance_options.nil?
327
388
  self.dalliance_options = {}
@@ -329,7 +390,7 @@ module Dalliance
329
390
  self.dalliance_options = self.dalliance_options.dup
330
391
  end
331
392
 
332
- self.dalliance_options.merge!(options)
393
+ self.dalliance_options.merge!(opts)
333
394
 
334
395
  include Dalliance
335
396
  end
@@ -7,7 +7,7 @@ module Dalliance
7
7
  ActiveSupport.on_load :active_record do
8
8
  include Dalliance::Glue
9
9
 
10
- ActiveRecord::ConnectionAdapters::TableDefinition.send(:include, Dalliance::Schema)
10
+ ActiveRecord::ConnectionAdapters::TableDefinition.include Dalliance::Schema
11
11
  end
12
12
  end
13
13
  end
@@ -46,20 +46,20 @@ module Dalliance
46
46
  #TODO: This is just a stopgap until I fix increment! to be thread-safe
47
47
  def progress
48
48
  begin
49
- _progress = (current_count.to_f / total_count.to_f * 100).to_i
49
+ current_progress = (current_count.to_f / total_count.to_f * 100).to_i
50
50
 
51
51
  #Handle an incorrect total_count...
52
- _progress = 100 if _progress > 100
52
+ current_progress = 100 if current_progress > 100
53
53
  rescue
54
54
  #what, are you diving by zero?
55
- _progress = 0
55
+ current_progress = 0
56
56
  end
57
57
 
58
- _progress
58
+ current_progress
59
59
  end
60
60
 
61
61
  def increment!
62
62
  Dalliance::ProgressMeter.increment_counter(:current_count, self.id)
63
63
  end
64
64
  end
65
- end
65
+ end
@@ -1,8 +1,8 @@
1
1
  module Dalliance
2
2
  module VERSION
3
3
  MAJOR = 0
4
- MINOR = 5
5
- TINY = 1
4
+ MINOR = 8
5
+ TINY = 2
6
6
  PRE = nil
7
7
 
8
8
  STRING = [MAJOR, MINOR, TINY, PRE].compact.join('.')
@@ -1,15 +1,20 @@
1
1
  module Dalliance
2
2
  module Workers
3
- if defined?(Rails) && ((::Rails::VERSION::MAJOR == 4 && ::Rails::VERSION::MINOR >= 2) || ::Rails::VERSION::MAJOR >= 5)
3
+ if defined?(Rails)
4
4
  class DelayedJob < ::ActiveJob::Base
5
5
  queue_as :dalliance
6
6
 
7
- def self.enqueue(instance, queue = 'dalliance')
8
- Dalliance::Workers::DelayedJob.set(queue: queue).perform_later(instance.class.name, instance.id)
7
+ def self.enqueue(instance, queue = 'dalliance', perform_method)
8
+ Dalliance::Workers::DelayedJob
9
+ .set(queue: queue)
10
+ .perform_later(instance.class.name, instance.id, perform_method.to_s)
9
11
  end
10
12
 
11
- def perform(instance_klass, instance_id)
12
- instance_klass.constantize.find(instance_id).dalliance_process(true)
13
+ def perform(instance_klass, instance_id, perform_method)
14
+ instance_klass
15
+ .constantize
16
+ .find(instance_id)
17
+ .send(perform_method, true)
13
18
  end
14
19
 
15
20
  #Delayed job automatically retries, so rescue the error
@@ -18,13 +23,19 @@ module Dalliance
18
23
  end
19
24
  end
20
25
  else
21
- class DelayedJob < Struct.new(:instance_klass, :instance_id)
22
- def self.enqueue(instance, queue = 'dalliance')
23
- ::Delayed::Job.enqueue(self.new(instance.class.name, instance.id), :queue => queue)
26
+ class DelayedJob < Struct.new(:instance_klass, :instance_id, :perform_method)
27
+ def self.enqueue(instance, queue = 'dalliance', perform_method)
28
+ ::Delayed::Job.enqueue(
29
+ self.new(instance.class.name, instance.id, perform_method),
30
+ :queue => queue
31
+ )
24
32
  end
25
33
 
26
34
  def perform
27
- instance_klass.constantize.find(instance_id).dalliance_process(true)
35
+ instance_klass
36
+ .constantize
37
+ .find(instance_id)
38
+ .send(perform_method, true)
28
39
  end
29
40
 
30
41
  #Delayed job automatically retries, so rescue the error
@@ -1,15 +1,20 @@
1
1
  module Dalliance
2
2
  module Workers
3
- if defined?(Rails) && ((::Rails::VERSION::MAJOR == 4 && ::Rails::VERSION::MINOR >= 2) || ::Rails::VERSION::MAJOR >= 5)
3
+ if defined?(Rails)
4
4
  class Resque < ::ActiveJob::Base
5
5
  queue_as :dalliance
6
6
 
7
- def self.enqueue(instance, queue = 'dalliance')
8
- Dalliance::Workers::Resque.set(queue: queue).perform_later(instance.class.name, instance.id)
7
+ def self.enqueue(instance, queue = 'dalliance', perform_method)
8
+ Dalliance::Workers::Resque
9
+ .set(queue: queue)
10
+ .perform_later(instance.class.name, instance.id, perform_method.to_s)
9
11
  end
10
12
 
11
- def perform(instance_klass, instance_id)
12
- instance_klass.constantize.find(instance_id).dalliance_process(true)
13
+ def perform(instance_klass, instance_id, perform_method)
14
+ instance_klass
15
+ .constantize
16
+ .find(instance_id)
17
+ .send(perform_method, true)
13
18
  end
14
19
 
15
20
  #Resque fails, so don't rescue the error
@@ -19,12 +24,15 @@ module Dalliance
19
24
  end
20
25
  else
21
26
  class Resque
22
- def self.enqueue(instance, queue = 'dalliance')
23
- ::Resque.enqueue_to(queue, self, instance.class.name, instance.id)
27
+ def self.enqueue(instance, queue = 'dalliance', perform_method)
28
+ ::Resque.enqueue_to(queue, self, instance.class.name, instance.id, perform_method.to_s)
24
29
  end
25
30
 
26
- def self.perform(instance_klass, instance_id)
27
- instance_klass.constantize.find(instance_id).dalliance_process(true)
31
+ def self.perform(instance_klass, instance_id, perform_method)
32
+ instance_klass
33
+ .constantize
34
+ .find(instance_id)
35
+ .send(perform_method, true)
28
36
  end
29
37
 
30
38
  #Resque fails, so don't rescue the error
@@ -77,6 +77,48 @@ RSpec.describe DallianceModel do
77
77
  expect(subject.dalliance_duration).not_to eq(nil)
78
78
  end
79
79
 
80
+ context 'reprocess' do
81
+ before(:all) do
82
+ DallianceModel.dalliance_options[:dalliance_method] = :dalliance_success_method
83
+ DallianceModel.dalliance_options[:worker_class] = Dalliance::Workers::DelayedJob
84
+ DallianceModel.dalliance_options[:queue] = 'dalliance'
85
+ end
86
+
87
+ before do
88
+ subject.dalliance_process
89
+ subject.reload
90
+ end
91
+
92
+ it 'successfully runs the dalliance_reprocess method' do
93
+ subject.dalliance_background_reprocess
94
+ Delayed::Worker.new(:queues => [:dalliance]).work_off
95
+ subject.reload
96
+
97
+ expect(subject).to be_successful
98
+ expect(Delayed::Job.count).to eq(0)
99
+ expect(subject.reprocessed_count).to eq(1)
100
+ end
101
+
102
+ it 'increases the total processing time counter' do
103
+ original_duration = subject.dalliance_duration
104
+ subject.dalliance_background_reprocess
105
+ Delayed::Worker.new(:queues => [:dalliance]).work_off
106
+ subject.reload
107
+
108
+ expect(subject.dalliance_duration).to be_between(original_duration, Float::INFINITY)
109
+ end
110
+
111
+ it "resets the dalliance_status to 'pending'" do
112
+ subject.update_column(:dalliance_status, 'processing_error')
113
+ expect { subject.dalliance_background_reprocess }
114
+ .to change(subject, :dalliance_status)
115
+ .to('pending')
116
+
117
+ Delayed::Worker.new(:queues => [:dalliance]).work_off
118
+ expect(subject).to be_successful
119
+ end
120
+ end
121
+
80
122
  context "another_queue" do
81
123
  let(:queue) { 'dalliance_2'}
82
124
 
@@ -114,6 +114,60 @@ RSpec.describe DallianceModel do
114
114
  end
115
115
  end
116
116
 
117
+ context 'reprocess' do
118
+ before :all do
119
+ DallianceModel.dalliance_options[:dalliance_method] = :dalliance_success_method
120
+ DallianceModel.dalliance_options[:worker_class] = Dalliance::Workers::Resque
121
+ DallianceModel.dalliance_options[:queue] = 'dalliance'
122
+ end
123
+
124
+ before do
125
+ subject.dalliance_process
126
+ subject.reload
127
+ end
128
+
129
+ it 'successfully runs the dalliance_reprocess method' do
130
+ Resque::Stat.clear(:processed)
131
+ Resque::Stat.clear(:failed)
132
+
133
+ subject.dalliance_background_reprocess
134
+ Resque::Worker.new(:dalliance).process
135
+ subject.reload
136
+
137
+ aggregate_failures do
138
+ expect(subject).to be_successful
139
+ expect(Resque.size(:dalliance)).to eq(0)
140
+ expect(Resque::Stat[:processed]).to eq(1)
141
+ expect(Resque::Stat[:failed]).to eq(0)
142
+ expect(subject.reprocessed_count).to eq(1)
143
+ end
144
+ end
145
+
146
+ it 'increases the total processing time counter' do
147
+ original_duration = subject.dalliance_duration
148
+ subject.dalliance_background_reprocess
149
+ Delayed::Worker.new(:queues => [:dalliance]).work_off
150
+ subject.reload
151
+
152
+ expect(subject.dalliance_duration).to be_between(original_duration, Float::INFINITY)
153
+ end
154
+
155
+ it "resets the dalliance_status to 'pending'" do
156
+ subject.update_column(:dalliance_status, 'processing_error')
157
+
158
+ Resque::Stat.clear(:processed)
159
+ Resque::Stat.clear(:failed)
160
+
161
+ expect { subject.dalliance_background_reprocess }
162
+ .to change(subject, :dalliance_status)
163
+ .to('pending')
164
+
165
+ Resque::Worker.new(:dalliance).process
166
+
167
+ expect(subject).to be_successful
168
+ end
169
+ end
170
+
117
171
  context "raise error" do
118
172
  before(:all) do
119
173
  DallianceModel.dalliance_options[:dalliance_method] = :dalliance_error_method
@@ -21,7 +21,7 @@ RSpec.describe 'Dalliance' do
21
21
 
22
22
  context "human_attribute_name" do
23
23
  it "should display the correct locale" do
24
- expect(DallianceModel.human_attribute_name(:dalliance_status)).to eq ('Status')
24
+ expect(DallianceModel.human_attribute_name(:dalliance_status)).to eq('Status')
25
25
  end
26
26
  end
27
27
 
@@ -44,7 +44,7 @@ RSpec.describe 'Dalliance' do
44
44
  end
45
45
 
46
46
  context "w/ args" do
47
- let(:queue) { Proc.new{ |a,b,c| 'dalliance_2' } }
47
+ let(:queue) { Proc.new{ |_a,_b,_c| 'dalliance_2' } }
48
48
 
49
49
  specify{ expect(subject.processing_queue).to eq(queue.call) }
50
50
  end