dalliance 0.5.1 → 0.8.2

Sign up to get free protection for your applications and to get access to all the features.
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