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,120 @@
1
+ # encoding: utf-8
2
+ require 'backgrounder/workers'
3
+
4
+ module CarrierWave
5
+ module Backgrounder
6
+ module ORM
7
+
8
+ ##
9
+ # Base class for all things orm
10
+ module Base
11
+
12
+ ##
13
+ # User#process_in_background will process and create versions in a background process.
14
+ #
15
+ # class User < ActiveRecord::Base
16
+ # mount_uploader :avatar, AvatarUploader
17
+ # process_in_background :avatar
18
+ # end
19
+ #
20
+ # The above adds a User#process_upload method which can be used at times when you want to bypass
21
+ # background storage and processing.
22
+ #
23
+ # @user.process_avatar = true
24
+ # @user.save
25
+ #
26
+ # You can also pass in your own workers using the second argument in case you need other things done
27
+ # during processing.
28
+ #
29
+ # class User < ActiveRecord::Base
30
+ # mount_uploader :avatar, AvatarUploader
31
+ # process_in_background :avatar, CustomWorker
32
+ # end
33
+ #
34
+ # In addition you can also add a column to the database appended by _processing with a type of boolean
35
+ # which can be used to check if processing is complete.
36
+ #
37
+ # def self.up
38
+ # add_column :users, :avatar_processing, :boolean
39
+ # end
40
+ #
41
+ def process_in_background(column, worker=::CarrierWave::Workers::ProcessAsset)
42
+ attr_accessor :"process_#{column}_upload"
43
+
44
+ mod = Module.new
45
+ include mod
46
+
47
+ _define_shared_backgrounder_methods(mod, column, worker)
48
+ end
49
+
50
+ ##
51
+ # #store_in_background will process, version and store uploads in a background process.
52
+ #
53
+ # class User < ActiveRecord::Base
54
+ # mount_uploader :avatar, AvatarUploader
55
+ # store_in_background :avatar
56
+ # end
57
+ #
58
+ # The above adds a User#process_<column>_upload method which can be used at times when you want to bypass
59
+ # background storage and processing.
60
+ #
61
+ # @user.process_avatar_upload = true
62
+ # @user.save
63
+ #
64
+ # You can also pass in your own workers using the second argument in case you need other things done
65
+ # during processing.
66
+ #
67
+ # class User < ActiveRecord::Base
68
+ # mount_uploader :avatar, AvatarUploader
69
+ # store_in_background :avatar, CustomWorker
70
+ # end
71
+ #
72
+ def store_in_background(column, worker=::CarrierWave::Workers::StoreAsset)
73
+ attr_accessor :"process_#{column}_upload"
74
+
75
+ mod = Module.new
76
+ include mod
77
+ mod.class_eval <<-RUBY, __FILE__, __LINE__ + 1
78
+ def remove_#{column}=(value)
79
+ super
80
+ self.process_#{column}_upload = true
81
+ end
82
+
83
+ def write_#{column}_identifier
84
+ super and return if process_#{column}_upload
85
+ self.#{column}_tmp = _mounter(:#{column}).cache_name if _mounter(:#{column}).cache_name
86
+ end
87
+
88
+ def store_#{column}!
89
+ super if process_#{column}_upload
90
+ end
91
+
92
+ RUBY
93
+
94
+ _define_shared_backgrounder_methods(mod, column, worker)
95
+ end
96
+
97
+ private
98
+
99
+ def _define_shared_backgrounder_methods(mod, column, worker)
100
+ mod.class_eval <<-RUBY, __FILE__, __LINE__ + 1
101
+ def #{column}_updated?; true; end
102
+
103
+ def set_#{column}_processing
104
+ self.#{column}_processing = true if respond_to?(:#{column}_processing)
105
+ end
106
+
107
+ def enqueue_#{column}_background_job?
108
+ !remove_#{column}? && !process_#{column}_upload && #{column}_updated?
109
+ end
110
+
111
+ def enqueue_#{column}_background_job
112
+ CarrierWave::Backgrounder.enqueue_for_backend(#{worker}, self.class.name, id.to_s, #{column}.mounted_as)
113
+ end
114
+ RUBY
115
+ end
116
+ end # Base
117
+
118
+ end #ORM
119
+ end #Backgrounder
120
+ end #CarrierWave
@@ -0,0 +1,63 @@
1
+ module CarrierWave
2
+ module Backgrounder
3
+ module ORM
4
+
5
+ module DataMapper
6
+ include CarrierWave::Backgrounder::ORM::Base
7
+
8
+ def process_in_background(column, worker=::CarrierWave::Workers::ProcessAsset)
9
+ super
10
+
11
+ class_eval <<-RUBY, __FILE__, __LINE__ + 1
12
+ def set_#{column}_processing
13
+ @#{column}_changed = attribute_dirty?(:#{column})
14
+ self.#{column}_processing = true if respond_to?(:#{column}_processing)
15
+ end
16
+ RUBY
17
+ end
18
+
19
+ def store_in_background(column, worker=::CarrierWave::Workers::StoreAsset)
20
+ super
21
+
22
+ class_eval <<-RUBY, __FILE__, __LINE__ + 1
23
+ def set_#{column}_changed
24
+ @#{column}_changed = attribute_dirty?(:#{column})
25
+ end
26
+
27
+ def write_#{column}_identifier
28
+ super and return if process_#{column}_upload
29
+ self.#{column}_tmp = _mounter(:#{column}).cache_name
30
+ end
31
+ RUBY
32
+ end
33
+
34
+ private
35
+
36
+ def _define_shared_backgrounder_methods(mod, column, worker)
37
+ before :save, :"set_#{column}_changed"
38
+ after :save, :"enqueue_#{column}_background_job"
39
+
40
+ super
41
+
42
+ class_eval <<-RUBY, __FILE__, __LINE__ + 1
43
+ attr_reader :#{column}_changed
44
+
45
+ def enqueue_#{column}_background_job
46
+ if enqueue_#{column}_background_job?
47
+ CarrierWave::Backgrounder.enqueue_for_backend(#{worker}, self.class.name, id, #{column}.mounted_as)
48
+ @#{column}_changed = false
49
+ end
50
+ end
51
+
52
+ def #{column}_updated?
53
+ #{column}_changed
54
+ end
55
+ RUBY
56
+ end
57
+ end # DataMapper
58
+
59
+ end #ORM
60
+ end #Backgrounder
61
+ end #CarrierWave
62
+
63
+ DataMapper::Model.append_extensions ::CarrierWave::Backgrounder::ORM::DataMapper
@@ -0,0 +1,25 @@
1
+ module CarrierWave
2
+ module Backgrounder
3
+ class Railtie < Rails::Railtie
4
+
5
+ initializer "carrierwave_backgrounder.active_record" do
6
+ ActiveSupport.on_load :active_record do
7
+ require 'backgrounder/orm/activemodel'
8
+ ::ActiveRecord::Base.extend CarrierWave::Backgrounder::ORM::ActiveModel
9
+ end
10
+ end
11
+
12
+ initializer "carrierwave_backgrounder.data_mapper", :before =>"data_mapper.add_to_prepare" do
13
+ require 'backgrounder/orm/data_mapper' if defined?(DataMapper)
14
+ end
15
+
16
+ initializer "carrierwave_backgrounder.mongoid" do
17
+ if defined?(Mongoid)
18
+ require 'backgrounder/orm/activemodel'
19
+ ::Mongoid::Document::ClassMethods.send(:include, ::CarrierWave::Backgrounder::ORM::ActiveModel)
20
+ end
21
+ end
22
+
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,94 @@
1
+ module CarrierWave
2
+ module Backgrounder
3
+ module Support
4
+ module Backends
5
+
6
+ def self.included(base)
7
+ base.extend ClassMethods
8
+ end
9
+
10
+ module ClassMethods
11
+ attr_reader :queue_options
12
+
13
+ def backend(queue_name=nil, args={})
14
+ return @backend if @backend
15
+ @queue_options = args
16
+ @backend = queue_name
17
+ end
18
+
19
+ def enqueue_for_backend(worker, class_name, subject_id, mounted_as)
20
+ self.send :"enqueue_#{backend}", worker, class_name, subject_id, mounted_as
21
+ end
22
+
23
+ private
24
+
25
+ def enqueue_active_job(worker, *args)
26
+ worker.perform(*args.map(&:to_s))
27
+ end
28
+
29
+ def enqueue_delayed_job(worker, *args)
30
+ worker_args = {}
31
+ if ::Delayed::Job.new.respond_to?(:queue)
32
+ worker_args[:queue] = queue_options[:queue] if queue_options[:queue]
33
+ worker_args[:priority] = queue_options[:priority] if queue_options[:priority]
34
+ ::Delayed::Job.enqueue worker.new(*args), worker_args
35
+ else
36
+ worker_args[:priority] = queue_options[:priority] if queue_options[:priority]
37
+ ::Delayed::Job.enqueue worker.new(*args), worker_args
38
+ if queue_options[:queue]
39
+ ::Rails.logger.warn("Queue name given but no queue column exists for Delayed::Job")
40
+ end
41
+ end
42
+ end
43
+
44
+ def enqueue_resque(worker, *args)
45
+ worker.instance_variable_set('@queue', queue_options[:queue] || :carrierwave)
46
+ ::Resque.enqueue worker, *args
47
+ end
48
+
49
+ def enqueue_sidekiq(worker, *args)
50
+ override_queue_name = worker.sidekiq_options['queue'] == 'default' || worker.sidekiq_options['queue'].nil?
51
+ args = sidekiq_queue_options(override_queue_name, 'class' => worker, 'args' => args)
52
+ worker.client_push(args)
53
+ end
54
+
55
+ def enqueue_girl_friday(worker, *args)
56
+ @girl_friday_queue ||= GirlFriday::WorkQueue.new(queue_options.delete(:queue) || :carrierwave, queue_options) do |msg|
57
+ worker = msg[:worker]
58
+ worker.perform
59
+ end
60
+ @girl_friday_queue << { :worker => worker.new(*args) }
61
+ end
62
+
63
+ def enqueue_sucker_punch(worker, *args)
64
+ worker.new.async.perform(*args)
65
+ end
66
+
67
+ def enqueue_qu(worker, *args)
68
+ worker.instance_variable_set('@queue', queue_options[:queue] || :carrierwave)
69
+ ::Qu.enqueue worker, *args
70
+ end
71
+
72
+ def enqueue_qc(worker, *args)
73
+ class_name, subject_id, mounted_as = args
74
+ ::QC.enqueue "#{worker.name}.perform", class_name, subject_id, mounted_as.to_s
75
+ end
76
+
77
+ def enqueue_immediate(worker, *args)
78
+ worker.new(*args).perform
79
+ end
80
+
81
+ def sidekiq_queue_options(override_queue_name, args)
82
+ if override_queue_name && queue_options[:queue]
83
+ args['queue'] = queue_options[:queue]
84
+ end
85
+ args['retry'] = queue_options[:retry] unless queue_options[:retry].nil?
86
+ args['timeout'] = queue_options[:timeout] if queue_options[:timeout]
87
+ args['backtrace'] = queue_options[:backtrace] if queue_options[:backtrace]
88
+ args
89
+ end
90
+ end
91
+ end
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,5 @@
1
+ module CarrierWave
2
+ module Backgrounder
3
+ VERSION = "1.0.0"
4
+ end
5
+ end
@@ -0,0 +1,6 @@
1
+ require 'backgrounder/workers/base'
2
+ require 'backgrounder/workers/class_methods'
3
+ require 'backgrounder/workers/process_asset_mixin'
4
+ require 'backgrounder/workers/store_asset_mixin'
5
+ require 'backgrounder/workers/process_asset'
6
+ require 'backgrounder/workers/store_asset'
@@ -0,0 +1,42 @@
1
+ # encoding: utf-8
2
+ module CarrierWave
3
+ module Workers
4
+
5
+ module Base
6
+ attr_accessor :klass, :id, :column, :record
7
+
8
+ def initialize(*args)
9
+ super(*args) unless self.class.superclass == Object
10
+ set_args(*args) if args.present?
11
+ end
12
+
13
+ def perform(*args)
14
+ set_args(*args) if args.present?
15
+ self.record = constantized_resource.find id
16
+ rescue *not_found_errors
17
+ end
18
+
19
+ private
20
+
21
+ def not_found_errors
22
+ [].tap do |errors|
23
+ errors << ::ActiveRecord::RecordNotFound if defined?(::ActiveRecord)
24
+ errors << ::Mongoid::Errors::DocumentNotFound if defined?(::Mongoid)
25
+ end
26
+ end
27
+
28
+ def set_args(klass, id, column)
29
+ self.klass, self.id, self.column = klass, id, column
30
+ end
31
+
32
+ def constantized_resource
33
+ klass.is_a?(String) ? klass.constantize : klass
34
+ end
35
+
36
+ def when_not_ready
37
+ end
38
+
39
+ end # Base
40
+
41
+ end # Workers
42
+ end # CarrierWave
@@ -0,0 +1,14 @@
1
+ # encoding: utf-8
2
+ module CarrierWave
3
+ module Workers
4
+
5
+ module ClassMethods
6
+
7
+ def perform(*args)
8
+ new(*args).perform
9
+ end
10
+
11
+ end # ClassMethods
12
+
13
+ end # Workers
14
+ end # Backgrounder
@@ -0,0 +1,10 @@
1
+ # encoding: utf-8
2
+ module CarrierWave
3
+ module Workers
4
+
5
+ class ProcessAsset
6
+ include CarrierWave::Workers::ProcessAssetMixin
7
+ end # ProcessAsset
8
+
9
+ end # Workers
10
+ end # Backgrounder
@@ -0,0 +1,28 @@
1
+ # encoding: utf-8
2
+ module CarrierWave
3
+ module Workers
4
+
5
+ module ProcessAssetMixin
6
+ include CarrierWave::Workers::Base
7
+
8
+ def self.included(base)
9
+ base.extend CarrierWave::Workers::ClassMethods
10
+ end
11
+
12
+ def perform(*args)
13
+ record = super(*args)
14
+
15
+ if record && record.send(:"#{column}").present?
16
+ record.send(:"process_#{column}_upload=", true)
17
+ if record.send(:"#{column}").recreate_versions! && record.respond_to?(:"#{column}_processing")
18
+ record.update_attribute :"#{column}_processing", false
19
+ end
20
+ else
21
+ when_not_ready
22
+ end
23
+ end
24
+
25
+ end # ProcessAssetMixin
26
+
27
+ end # Workers
28
+ end # Backgrounder
@@ -0,0 +1,10 @@
1
+ # encoding: utf-8
2
+ module CarrierWave
3
+ module Workers
4
+
5
+ class StoreAsset
6
+ include CarrierWave::Workers::StoreAssetMixin
7
+ end # StoreAsset
8
+
9
+ end # Workers
10
+ end # Backgrounder
@@ -0,0 +1,43 @@
1
+ # encoding: utf-8
2
+ module CarrierWave
3
+ module Workers
4
+
5
+ module StoreAssetMixin
6
+ include CarrierWave::Workers::Base
7
+
8
+ def self.included(base)
9
+ base.extend CarrierWave::Workers::ClassMethods
10
+ end
11
+
12
+ attr_reader :cache_path, :tmp_directory
13
+
14
+ def perform(*args)
15
+ record = super(*args)
16
+
17
+ if record && record.send(:"#{column}_tmp")
18
+ store_directories(record)
19
+ record.send :"process_#{column}_upload=", true
20
+ record.send :"#{column}_tmp=", nil
21
+ record.send :"#{column}_processing=", false if record.respond_to?(:"#{column}_processing")
22
+ File.open(cache_path) { |f| record.send :"#{column}=", f }
23
+ if record.save!
24
+ FileUtils.rm_r(tmp_directory, :force => true)
25
+ end
26
+ else
27
+ when_not_ready
28
+ end
29
+ end
30
+
31
+ private
32
+
33
+ def store_directories(record)
34
+ asset, asset_tmp = record.send(:"#{column}"), record.send(:"#{column}_tmp")
35
+ cache_directory = File.expand_path(asset.cache_dir, asset.root)
36
+ @cache_path = File.join(cache_directory, asset_tmp)
37
+ @tmp_directory = File.join(cache_directory, asset_tmp.split("/").first)
38
+ end
39
+
40
+ end # StoreAssetMixin
41
+
42
+ end # Workers
43
+ end # Backgrounder