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