carrierwave_backgrounder_revived 1.0.0
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.
- checksums.yaml +7 -0
- data/.gitignore +5 -0
- data/.rspec +2 -0
- data/.travis.yml +15 -0
- data/CHANGELOG.md +99 -0
- data/Gemfile +4 -0
- data/README.md +229 -0
- data/Rakefile +12 -0
- data/carrierwave_backgrounder.gemspec +25 -0
- data/lib/backgrounder/delay.rb +26 -0
- data/lib/backgrounder/orm/activemodel.rb +36 -0
- data/lib/backgrounder/orm/base.rb +120 -0
- data/lib/backgrounder/orm/data_mapper.rb +63 -0
- data/lib/backgrounder/railtie.rb +25 -0
- data/lib/backgrounder/support/backends.rb +94 -0
- data/lib/backgrounder/version.rb +5 -0
- data/lib/backgrounder/workers.rb +6 -0
- data/lib/backgrounder/workers/base.rb +42 -0
- data/lib/backgrounder/workers/class_methods.rb +14 -0
- data/lib/backgrounder/workers/process_asset.rb +10 -0
- data/lib/backgrounder/workers/process_asset_mixin.rb +28 -0
- data/lib/backgrounder/workers/store_asset.rb +10 -0
- data/lib/backgrounder/workers/store_asset_mixin.rb +43 -0
- data/lib/carrierwave_backgrounder.rb +35 -0
- data/lib/generators/carrierwave_backgrounder/USAGE +8 -0
- data/lib/generators/carrierwave_backgrounder/install_generator.rb +20 -0
- data/lib/generators/carrierwave_backgrounder/templates/config/initializers/carrierwave_backgrounder.rb +10 -0
- data/spec/backgrounder/orm/activemodel_spec.rb +97 -0
- data/spec/backgrounder/orm/base_spec.rb +74 -0
- data/spec/backgrounder/support/backends_spec.rb +234 -0
- data/spec/backgrounder/workers/fixtures/images/test.jpg +0 -0
- data/spec/backgrounder/workers/process_asset_spec.rb +70 -0
- data/spec/backgrounder/workers/store_asset_spec.rb +137 -0
- data/spec/spec_helper.rb +20 -0
- data/spec/support/backend_constants.rb +58 -0
- data/spec/support/mock_worker.rb +22 -0
- 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,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,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,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
|