2018-05-09 12:01:36 +05:30
# frozen_string_literal: true
module ObjectStorage
class MigrateUploadsWorker
include ApplicationWorker
include ObjectStorageQueue
SanityCheckError = Class . new ( StandardError )
class MigrationResult
attr_reader :upload
attr_accessor :error
def initialize ( upload , error = nil )
@upload , @error = upload , error
end
def success?
error . nil?
end
def to_s
2019-07-31 22:56:46 +05:30
success? ? _ ( " Migration successful. " ) : _ ( " Error while migrating %{upload_id}: %{error_message} " ) % { upload_id : upload . id , error_message : error . message }
2018-05-09 12:01:36 +05:30
end
end
module Report
class MigrationFailures < StandardError
attr_reader :errors
def initialize ( errors )
@errors = errors
end
def message
errors . map ( & :message ) . join ( " \n " )
end
end
2019-09-30 21:07:59 +05:30
# rubocop:disable Gitlab/RailsLogger
2018-05-09 12:01:36 +05:30
def report! ( results )
success , failures = results . partition ( & :success? )
Rails . logger . info header ( success , failures )
Rails . logger . warn failures ( failures )
raise MigrationFailures . new ( failures . map ( & :error ) ) if failures . any?
end
2019-09-30 21:07:59 +05:30
# rubocop:enable Gitlab/RailsLogger
2018-05-09 12:01:36 +05:30
def header ( success , failures )
2019-07-31 22:56:46 +05:30
_ ( " Migrated %{success_count}/%{total_count} files. " ) % { success_count : success . count , total_count : success . count + failures . count }
2018-05-09 12:01:36 +05:30
end
def failures ( failures )
failures . map { | f | " \t #{ f } " } . join ( '\n' )
end
end
include Report
2018-12-05 23:21:45 +05:30
# rubocop: disable CodeReuse/ActiveRecord
2018-05-09 12:01:36 +05:30
def self . enqueue! ( uploads , model_class , mounted_as , to_store )
sanity_check! ( uploads , model_class , mounted_as )
perform_async ( uploads . ids , model_class . to_s , mounted_as , to_store )
end
2018-12-05 23:21:45 +05:30
# rubocop: enable CodeReuse/ActiveRecord
2018-05-09 12:01:36 +05:30
# We need to be sure all the uploads are for the same uploader and model type
# and that the mount point exists if provided.
#
def self . sanity_check! ( uploads , model_class , mounted_as )
upload = uploads . first
uploader_class = upload . uploader . constantize
uploader_types = uploads . map ( & :uploader ) . uniq
model_types = uploads . map ( & :model_type ) . uniq
model_has_mount = mounted_as . nil? || model_class . uploaders [ mounted_as ] == uploader_class
2019-07-31 22:56:46 +05:30
raise ( SanityCheckError , _ ( " Multiple uploaders found: %{uploader_types} " ) % { uploader_types : uploader_types } ) unless uploader_types . count == 1
raise ( SanityCheckError , _ ( " Multiple model types found: %{model_types} " ) % { model_types : model_types } ) unless model_types . count == 1
raise ( SanityCheckError , _ ( " Mount point %{mounted_as} not found in %{model_class}. " ) % { mounted_as : mounted_as , model_class : model_class } ) unless model_has_mount
2018-05-09 12:01:36 +05:30
end
2018-12-05 23:21:45 +05:30
# rubocop: disable CodeReuse/ActiveRecord
2018-05-09 12:01:36 +05:30
def perform ( * args )
args_check! ( args )
( ids , model_type , mounted_as , to_store ) = args
@model_class = model_type . constantize
@mounted_as = mounted_as & . to_sym
@to_store = to_store
uploads = Upload . preload ( :model ) . where ( id : ids )
sanity_check! ( uploads )
results = migrate ( uploads )
report! ( results )
rescue SanityCheckError = > e
# do not retry: the job is insane
2019-09-30 21:07:59 +05:30
Rails . logger . warn " #{ self . class } : Sanity check error ( #{ e . message } ) " # rubocop:disable Gitlab/RailsLogger
2018-05-09 12:01:36 +05:30
end
2018-12-05 23:21:45 +05:30
# rubocop: enable CodeReuse/ActiveRecord
2018-05-09 12:01:36 +05:30
def sanity_check! ( uploads )
self . class . sanity_check! ( uploads , @model_class , @mounted_as )
end
def args_check! ( args )
return if args . count == 4
case args . count
2019-07-31 22:56:46 +05:30
when 3 then raise SanityCheckError , _ ( " Job is missing the `model_type` argument. " )
2018-05-09 12:01:36 +05:30
else
2019-07-31 22:56:46 +05:30
raise SanityCheckError , _ ( " Job has wrong arguments format. " )
2018-05-09 12:01:36 +05:30
end
end
def build_uploaders ( uploads )
uploads . map { | upload | upload . build_uploader ( @mounted_as ) }
end
def migrate ( uploads )
build_uploaders ( uploads ) . map ( & method ( :process_uploader ) )
end
def process_uploader ( uploader )
MigrationResult . new ( uploader . upload ) . tap do | result |
2019-07-07 11:18:12 +05:30
uploader . migrate! ( @to_store )
rescue = > e
result . error = e
2018-05-09 12:01:36 +05:30
end
end
end
end