carrierwave_backgrounder_revived 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (37) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +5 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +15 -0
  5. data/CHANGELOG.md +99 -0
  6. data/Gemfile +4 -0
  7. data/README.md +229 -0
  8. data/Rakefile +12 -0
  9. data/carrierwave_backgrounder.gemspec +25 -0
  10. data/lib/backgrounder/delay.rb +26 -0
  11. data/lib/backgrounder/orm/activemodel.rb +36 -0
  12. data/lib/backgrounder/orm/base.rb +120 -0
  13. data/lib/backgrounder/orm/data_mapper.rb +63 -0
  14. data/lib/backgrounder/railtie.rb +25 -0
  15. data/lib/backgrounder/support/backends.rb +94 -0
  16. data/lib/backgrounder/version.rb +5 -0
  17. data/lib/backgrounder/workers.rb +6 -0
  18. data/lib/backgrounder/workers/base.rb +42 -0
  19. data/lib/backgrounder/workers/class_methods.rb +14 -0
  20. data/lib/backgrounder/workers/process_asset.rb +10 -0
  21. data/lib/backgrounder/workers/process_asset_mixin.rb +28 -0
  22. data/lib/backgrounder/workers/store_asset.rb +10 -0
  23. data/lib/backgrounder/workers/store_asset_mixin.rb +43 -0
  24. data/lib/carrierwave_backgrounder.rb +35 -0
  25. data/lib/generators/carrierwave_backgrounder/USAGE +8 -0
  26. data/lib/generators/carrierwave_backgrounder/install_generator.rb +20 -0
  27. data/lib/generators/carrierwave_backgrounder/templates/config/initializers/carrierwave_backgrounder.rb +10 -0
  28. data/spec/backgrounder/orm/activemodel_spec.rb +97 -0
  29. data/spec/backgrounder/orm/base_spec.rb +74 -0
  30. data/spec/backgrounder/support/backends_spec.rb +234 -0
  31. data/spec/backgrounder/workers/fixtures/images/test.jpg +0 -0
  32. data/spec/backgrounder/workers/process_asset_spec.rb +70 -0
  33. data/spec/backgrounder/workers/store_asset_spec.rb +137 -0
  34. data/spec/spec_helper.rb +20 -0
  35. data/spec/support/backend_constants.rb +58 -0
  36. data/spec/support/mock_worker.rb +22 -0
  37. metadata +151 -0
@@ -0,0 +1,35 @@
1
+ require 'active_support/core_ext/object'
2
+ require 'backgrounder/support/backends'
3
+ require 'backgrounder/orm/base'
4
+ require 'backgrounder/delay'
5
+
6
+ module CarrierWave
7
+ module Backgrounder
8
+ include Support::Backends
9
+
10
+ def self.configure
11
+ yield self
12
+ case @backend
13
+ when :sidekiq
14
+ require 'sidekiq'
15
+ ::CarrierWave::Workers::ProcessAsset.class_eval do
16
+ include ::Sidekiq::Worker
17
+ end
18
+ ::CarrierWave::Workers::StoreAsset.class_eval do
19
+ include ::Sidekiq::Worker
20
+ end
21
+ when :sucker_punch
22
+ require 'sucker_punch'
23
+ ::CarrierWave::Workers::ProcessAsset.class_eval do
24
+ include ::SuckerPunch::Job
25
+ end
26
+ ::CarrierWave::Workers::StoreAsset.class_eval do
27
+ include ::SuckerPunch::Job
28
+ end
29
+ end
30
+ end
31
+
32
+ end
33
+ end
34
+
35
+ require 'backgrounder/railtie' if defined?(Rails)
@@ -0,0 +1,8 @@
1
+ Description:
2
+ To copy CarrierWaveBackgrounder initializer to your Rails App, with some configuration values, run the following:
3
+
4
+ Example:
5
+ rails generate carrierwave_backgrounder:install
6
+
7
+ This will create:
8
+ config/initializer/carrierwave_backgrounder.rb
@@ -0,0 +1,20 @@
1
+ module CarrierwaveBackgrounder
2
+ module Generators
3
+ class InstallGenerator < Rails::Generators::Base
4
+ source_root File.expand_path('../templates', __FILE__)
5
+
6
+ def copy_config
7
+ template "config/initializers/carrierwave_backgrounder.rb"
8
+ end
9
+
10
+ def info_config
11
+ puts <<-EOF
12
+
13
+ \e[33mBy default :delayed_job is used as the backend for carrierwave_backgrounder with :carrierwave as the queue name.
14
+ To change this, edit config/initializers/carrierwave_backgrounder.rb.\e[0m
15
+
16
+ EOF
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,10 @@
1
+ CarrierWave::Backgrounder.configure do |c|
2
+ c.backend :delayed_job, queue: :carrierwave
3
+ # c.backend :active_job, queue: :carrierwave
4
+ # c.backend :resque, queue: :carrierwave
5
+ # c.backend :sidekiq, queue: :carrierwave
6
+ # c.backend :girl_friday, queue: :carrierwave
7
+ # c.backend :sucker_punch, queue: :carrierwave
8
+ # c.backend :qu, queue: :carrierwave
9
+ # c.backend :qc
10
+ end
@@ -0,0 +1,97 @@
1
+ require 'spec_helper'
2
+ require 'ostruct'
3
+ require 'backgrounder/orm/activemodel'
4
+
5
+ RSpec.describe CarrierWave::Backgrounder::ORM::ActiveModel do
6
+ before do
7
+ @mock_class = Class.new do
8
+ def self.before_save(method, opts); nil; end
9
+ def self.after_commit(method, opts); nil; end
10
+ def avatar_changed?; nil; end
11
+ def remote_avatar_url; OpenStruct.new(:present? => true); end
12
+ def remove_avatar?; false; end
13
+ def previous_changes; {}; end
14
+ def self.uploader_options; {}; end
15
+ end
16
+
17
+ @mock_class.extend CarrierWave::Backgrounder::ORM::ActiveModel
18
+ end
19
+
20
+ describe '.store_in_background' do
21
+ context 'setting up callbacks' do
22
+ it 'creates an after_commit hook' do
23
+ expect(@mock_class).to receive(:after_commit).with(:enqueue_avatar_background_job, :if => :enqueue_avatar_background_job?)
24
+ @mock_class.store_in_background :avatar
25
+ end
26
+ end
27
+ end
28
+
29
+ describe '.process_in_background' do
30
+ context 'setting up callbacks' do
31
+ it 'creates a before_save hook' do
32
+ expect(@mock_class).to receive(:before_save).with(:set_avatar_processing, :if => :enqueue_avatar_background_job?)
33
+ @mock_class.process_in_background :avatar
34
+ end
35
+
36
+ it 'creates an after_save hook' do
37
+ expect(@mock_class).to receive(:after_commit).with(:enqueue_avatar_background_job, :if => :enqueue_avatar_background_job?)
38
+ @mock_class.process_in_background :avatar
39
+ end
40
+ end
41
+ end
42
+
43
+ describe '#trigger_column_background_processing?' do
44
+ let(:instance) { @mock_class.new }
45
+
46
+ before do
47
+ @mock_class.process_in_background :avatar
48
+ end
49
+
50
+ context 'mount_on option is set' do
51
+ before do
52
+ options_hash = {:avatar => {:mount_on => :some_other_column}}
53
+ expect(@mock_class).to receive(:uploader_options).and_return(options_hash)
54
+ end
55
+
56
+ it "returns true if alternate column is changed" do
57
+ expect(instance).to receive(:some_other_column_changed?).and_return(true)
58
+ expect(instance.avatar_updated?).to be_truthy
59
+ end
60
+ end
61
+
62
+ it "returns true if process_avatar_upload is false" do
63
+ expect(instance).to receive(:process_avatar_upload)
64
+ expect(instance.enqueue_avatar_background_job?).to be_truthy
65
+ end
66
+
67
+ it "calls column_changed?" do
68
+ expect(instance).to receive(:process_avatar_upload).and_return(false)
69
+ expect(instance).to receive(:avatar_changed?)
70
+ expect(instance.enqueue_avatar_background_job?).to be_truthy
71
+ end
72
+
73
+ it "calls previous_changes" do
74
+ expect(instance).to receive(:process_avatar_upload).and_return(false)
75
+ expect(instance).to receive(:avatar_changed?).and_return(false)
76
+ expect(instance).to receive(:previous_changes).and_return({:avatar => true})
77
+ expect(instance.enqueue_avatar_background_job?).to be_truthy
78
+ end
79
+
80
+ it "calls avatar_remote_url" do
81
+ expect(instance).to receive(:process_avatar_upload).and_return(false)
82
+ expect(instance).to receive(:avatar_changed?).and_return(false)
83
+ expect(instance).to receive(:previous_changes).and_return({})
84
+ expect(instance).to receive(:remote_avatar_url).and_return('yup')
85
+ expect(instance.enqueue_avatar_background_job?).to be_truthy
86
+ end
87
+
88
+ it "calls avatar_cache" do
89
+ expect(instance).to receive(:process_avatar_upload).and_return(false)
90
+ expect(instance).to receive(:avatar_changed?).and_return(false)
91
+ expect(instance).to receive(:previous_changes).and_return({})
92
+ expect(instance).to receive(:remote_avatar_url).and_return(nil)
93
+ expect(instance).to receive(:avatar_cache).and_return('yup')
94
+ expect(instance.enqueue_avatar_background_job?).to be_truthy
95
+ end
96
+ end
97
+ end
@@ -0,0 +1,74 @@
1
+ require 'spec_helper'
2
+
3
+
4
+ RSpec.describe CarrierWave::Backgrounder::ORM::Base do
5
+ before do
6
+ @mock_class = Class.new do
7
+ def self.before_save(method, opts); nil; end
8
+ def self.after_commit(method, opts); nil; end
9
+ end
10
+
11
+ @mock_class.extend CarrierWave::Backgrounder::ORM::Base
12
+ end
13
+
14
+ it 'mixes in the two DSL methods' do
15
+ expect(@mock_class).to respond_to(:process_in_background)
16
+ expect(@mock_class).to respond_to(:store_in_background)
17
+ end
18
+
19
+ describe '.process_in_background' do
20
+ context 'including new methods' do
21
+ before do
22
+ @mock_class.process_in_background :avatar
23
+ @instance = @mock_class.new
24
+ end
25
+
26
+ it 'creates a processing enabled accessor' do
27
+ expect(@instance).to respond_to(:process_avatar_upload)
28
+ expect(@instance).to respond_to(:process_avatar_upload=)
29
+ end
30
+
31
+ it 'create a setter for the processing attribute' do
32
+ expect(@instance).to respond_to(:set_avatar_processing)
33
+ end
34
+
35
+ it 'create a background job queuer' do
36
+ expect(@instance).to respond_to(:enqueue_avatar_background_job)
37
+ end
38
+
39
+ it 'create a trigger interrogator' do
40
+ expect(@instance).to respond_to(:enqueue_avatar_background_job?)
41
+ end
42
+ end
43
+ end
44
+
45
+ describe 'store in background' do
46
+ describe 'including new methods' do
47
+ before do
48
+ @mock_class.store_in_background :avatar
49
+ @instance = @mock_class.new
50
+ end
51
+
52
+ it 'creates a processing enabled accessor' do
53
+ expect(@instance).to respond_to(:process_avatar_upload)
54
+ expect(@instance).to respond_to(:process_avatar_upload=)
55
+ end
56
+
57
+ it 'overrides the write column identifier method from carrierwave' do
58
+ expect(@instance).to respond_to(:write_avatar_identifier)
59
+ end
60
+
61
+ it 'overrides the store column method from carrierwave' do
62
+ expect(@instance).to respond_to(:store_avatar!)
63
+ end
64
+
65
+ it 'create a background job queuer' do
66
+ expect(@instance).to respond_to(:enqueue_avatar_background_job)
67
+ end
68
+
69
+ it 'create a trigger interrogator' do
70
+ expect(@instance).to respond_to(:enqueue_avatar_background_job?)
71
+ end
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,234 @@
1
+ require 'spec_helper'
2
+ require 'support/backend_constants'
3
+ require 'support/mock_worker'
4
+
5
+ module CarrierWave::Backgrounder
6
+ RSpec.describe Support::Backends do
7
+ let(:mock_module) { Module.new }
8
+
9
+ before do
10
+ mock_module.send :include, Support::Backends
11
+ end
12
+
13
+ describe 'setting backend' do
14
+ it 'using #backend=' do
15
+ expect {
16
+ mock_module.backend = :delayed_job
17
+ }.to raise_error(NoMethodError)
18
+ end
19
+
20
+ it 'using #backend' do
21
+ mock_module.backend(:delayed_job)
22
+ expect(mock_module.backend).to eql(:delayed_job)
23
+ end
24
+
25
+ it 'allows passing of queue_options' do
26
+ mock_module.backend(:delayed_job, :queue => :awesome_queue)
27
+ expect(mock_module.queue_options).to eql({:queue => :awesome_queue})
28
+ end
29
+ end
30
+
31
+ describe '#enqueue_for_backend' do
32
+ let!(:worker) { MockWorker.new('FakeClass', 1, :image) }
33
+
34
+ context 'active_job' do
35
+ let(:args) { ['FakeClass', 1, :image] }
36
+
37
+ it 'invokes perform with string arguments' do
38
+ expect(MockWorker).to receive(:perform).with('FakeClass', '1', 'image')
39
+ mock_module.backend :active_job
40
+ mock_module.enqueue_for_backend(MockWorker, *args)
41
+ end
42
+ end
43
+
44
+ context 'delayed_job' do
45
+ before do
46
+ @mock_worker = Class.new do
47
+ def self.perform(*args); new(*args).perform; end
48
+ end
49
+
50
+ allow(MockWorker).to receive(:new).and_return(worker)
51
+ end
52
+
53
+ context 'queue column exists' do
54
+ it 'does not pass the queue name if none passed to #backend' do
55
+ mock_module.backend :delayed_job
56
+ expect(Delayed::Job).to receive(:enqueue).with(worker, {})
57
+ mock_module.enqueue_for_backend MockWorker, 'FakeClass', 1, :image
58
+ end
59
+
60
+ it 'sets the queue name to the queue name passed to #backend' do
61
+ mock_module.backend :delayed_job, :queue => :awesome_queue
62
+ expect(Delayed::Job).to receive(:enqueue).with(worker, :queue => :awesome_queue)
63
+ mock_module.enqueue_for_backend MockWorker, 'FakeClass', 1, :image
64
+ end
65
+ end
66
+
67
+ context 'priority set in config' do
68
+ it 'sets the priority which is passed to #backend' do
69
+ mock_module.backend :delayed_job, :priority => 5
70
+ expect(Delayed::Job).to receive(:enqueue).with(worker, :priority => 5)
71
+ mock_module.enqueue_for_backend MockWorker, 'FakeClass', 1, :image
72
+ end
73
+ end
74
+
75
+ context 'queue column does not exist' do
76
+ before do
77
+ column_names = Delayed::Job.column_names.tap { |cn| cn.delete('queue') }
78
+ allow(Delayed::Job).to receive(:column_names).and_return(column_names)
79
+ Delayed::Job.class_eval { remove_method(:queue) }
80
+ end
81
+
82
+ after do
83
+ Delayed::Job.class_eval { define_method(:queue) { nil } }
84
+ end
85
+
86
+ it 'does not pass a queue name if none passed to #backend' do
87
+ mock_module.backend :delayed_job
88
+ expect(Delayed::Job).to receive(:enqueue).with(worker, {})
89
+ mock_module.enqueue_for_backend MockWorker, 'FakeClass', 1, :image
90
+ end
91
+
92
+ it 'does not pass a queue name and logs a warning message if a queue name is passed to #backend' do
93
+ mock_module.backend :delayed_job, :queue => :awesome_queue
94
+ expect(Rails.logger).to receive(:warn).with(instance_of(String))
95
+ expect(Delayed::Job).to receive(:enqueue).with(worker, {})
96
+ mock_module.enqueue_for_backend MockWorker, 'FakeClass', 1, :image
97
+ end
98
+ end
99
+ end
100
+
101
+ context 'resque' do
102
+ let(:args) { [MockWorker, 'FakeClass', 1, :image] }
103
+
104
+ before do
105
+ allow(Resque).to receive(:enqueue).with(*args)
106
+ end
107
+
108
+ it 'sets a variable with the queue name, defaults to :carrierwave' do
109
+ mock_module.backend :resque
110
+ mock_module.enqueue_for_backend(*args)
111
+ expect(MockWorker.instance_variable_get '@queue').to eql(:carrierwave)
112
+ end
113
+
114
+ it 'sets a variable to the queue name passed to #backend' do
115
+ mock_module.backend :resque, :queue => :awesome_queue
116
+ mock_module.enqueue_for_backend(*args)
117
+ expect(MockWorker.instance_variable_get '@queue').to eql(:awesome_queue)
118
+ end
119
+ end
120
+
121
+ context 'sidekiq' do
122
+ let(:args) { ['FakeClass', 1, :image] }
123
+
124
+ it 'invokes client_push on the class with passed args' do
125
+ expect(MockSidekiqWorker).to receive(:client_push).with({ 'class' => MockSidekiqWorker, 'args' => args })
126
+ mock_module.backend :sidekiq
127
+ mock_module.enqueue_for_backend(MockSidekiqWorker, *args)
128
+ end
129
+
130
+ it 'invokes client_push and includes the options passed to backend' do
131
+ expect(MockSidekiqWorker).to receive(:client_push).with({ 'class' => MockSidekiqWorker,
132
+ 'retry' => false,
133
+ 'timeout' => 60,
134
+ 'queue' => :awesome_queue,
135
+ 'args' => args })
136
+ options = {:retry => false, :timeout => 60, :queue => :awesome_queue}
137
+ mock_module.backend :sidekiq, options
138
+ mock_module.enqueue_for_backend(MockSidekiqWorker, *args)
139
+ end
140
+
141
+ it 'does not override queue name if set it worker' do
142
+ expect(MockNamedSidekiqWorker).to receive(:client_push).with({ 'class' => MockNamedSidekiqWorker,
143
+ 'retry' => false,
144
+ 'timeout' => 60,
145
+ 'args' => args })
146
+ options = {:retry => false, :timeout => 60}
147
+ mock_module.backend :sidekiq, options
148
+ mock_module.enqueue_for_backend(MockNamedSidekiqWorker, *args)
149
+ end
150
+ end
151
+
152
+ context 'girl_friday' do
153
+ let(:args) { [MockWorker, 'FakeClass', 1, :image] }
154
+
155
+ it 'instantiates a GirlFriday work queue if one does not exist' do
156
+ mock_module.backend :girl_friday
157
+ expect(GirlFriday::WorkQueue).to receive(:new).with(:carrierwave, {}).and_return([])
158
+ mock_module.enqueue_for_backend(*args)
159
+ end
160
+
161
+ it 'instantiates a GirlFriday work queue passing the args to the queue' do
162
+ mock_module.backend :girl_friday, :queue => :awesome_queue, :size => 3
163
+ expect(GirlFriday::WorkQueue).to receive(:new).with(:awesome_queue, {:size => 3}).and_return([])
164
+ mock_module.enqueue_for_backend(*args)
165
+ end
166
+
167
+ it 'does not instantiate a GirlFriday work queue if one exists' do
168
+ mock_module.backend :girl_friday
169
+ mock_module.instance_variable_set('@girl_friday_queue', [])
170
+ expect(GirlFriday::WorkQueue).to receive(:new).never
171
+ mock_module.enqueue_for_backend(*args)
172
+ end
173
+
174
+ it 'add a worker to the girl_friday queue' do
175
+ expected = [{ :worker => MockWorker.new('FakeClass', 1, :image) }]
176
+ mock_module.backend :girl_friday
177
+ mock_module.instance_variable_set('@girl_friday_queue', [])
178
+ mock_module.enqueue_for_backend(*args)
179
+ expect(mock_module.instance_variable_get '@girl_friday_queue').to eql(expected)
180
+ end
181
+ end
182
+
183
+ context 'sucker_punch' do
184
+ let(:args) { [MockWorker, 'FakeClass', 1, :image] }
185
+ let(:job) { double('job') }
186
+
187
+ it 'invokes a new worker' do
188
+ expect(MockWorker).to receive(:new).and_return(worker)
189
+ expect(worker).to receive(:async).and_return(job)
190
+ expect(job).to receive(:perform).with('FakeClass', 1, :image)
191
+ mock_module.backend :sucker_punch
192
+ mock_module.enqueue_for_backend(*args)
193
+ end
194
+ end
195
+
196
+ context 'qu' do
197
+ let(:args) { [MockWorker, 'FakeClass', 1, :image] }
198
+ before do
199
+ allow(Qu).to receive(:enqueue).with(*args)
200
+ end
201
+
202
+ it 'sets a variable with the queue name, defaults to :carrierwave' do
203
+ mock_module.backend :qu
204
+ mock_module.enqueue_for_backend(*args)
205
+ expect(MockWorker.instance_variable_get '@queue').to eql(:carrierwave)
206
+ end
207
+
208
+ it 'sets a variable to the queue name passed to #backend' do
209
+ mock_module.backend :qu, :queue => :awesome_queue
210
+ mock_module.enqueue_for_backend(*args)
211
+ expect(MockWorker.instance_variable_get '@queue').to eql(:awesome_queue)
212
+ end
213
+ end
214
+
215
+ context 'qc' do
216
+ it 'calls enqueue with the passed args' do
217
+ expect(QC).to receive(:enqueue).with("MockWorker.perform", 'FakeClass', 1, 'image')
218
+ mock_module.backend :qc
219
+ mock_module.enqueue_for_backend(MockWorker, 'FakeClass', 1, :image)
220
+ end
221
+ end
222
+
223
+ context 'immediate' do
224
+ it 'instantiates a worker passing the args and calls perform' do
225
+ worker = double('Worker')
226
+ expect(MockWorker).to receive(:new).with('FakeClass', 1, :image).and_return(worker)
227
+ expect(worker).to receive(:perform)
228
+ mock_module.backend :immediate
229
+ mock_module.enqueue_for_backend(MockWorker, 'FakeClass', 1, :image)
230
+ end
231
+ end
232
+ end
233
+ end
234
+ end