2018-05-09 12:01:36 +05:30
# frozen_string_literal: true
2020-04-08 14:13:33 +05:30
# rubocop:disable Scalability/IdempotentWorker
2018-05-09 12:01:36 +05:30
module ObjectStorage
class MigrateUploadsWorker
include ApplicationWorker
include ObjectStorageQueue
2019-12-21 20:55:43 +05:30
feature_category_not_owned!
2020-06-23 00:09:42 +05:30
loggable_arguments 0 , 1 , 2 , 3
2019-12-21 20:55:43 +05:30
2018-05-09 12:01:36 +05:30
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
def report! ( results )
success , failures = results . partition ( & :success? )
2020-11-24 15:15:51 +05:30
Gitlab :: AppLogger . info header ( success , failures )
Gitlab :: AppLogger . warn failures ( failures )
2018-05-09 12:01:36 +05:30
raise MigrationFailures . new ( failures . map ( & :error ) ) if failures . any?
end
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
2020-11-24 15:15:51 +05:30
Gitlab :: AppLogger . warn " #{ self . class } : Sanity check error ( #{ e . message } ) "
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 )
2019-12-21 20:55:43 +05:30
uploads . map { | upload | upload . retrieve_uploader ( @mounted_as ) }
2018-05-09 12:01:36 +05:30
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
2020-04-08 14:13:33 +05:30
# rubocop:enable Scalability/IdempotentWorker