У меня есть случай, когда пользователь может загрузить несколько больших файлов PDF на наш сервер, где мы преобразуем их в набор изображений
Я думаю, просто подумав, что я создал асинхронный исполнитель для каждого метода преобразования файлов, но я точно не знаю, работает ли он правильно, или моя реализация неэффективна, как я думал.
Я создал асинхронный исполнитель в моем проекте. Использование @Configuration
@EnableAsync -> созданный файл конфигурации
И пометил мои функции внутри службы с помощью @Async ("asyncExecutor"), которые возвращают CompletableFuture>
Ниже код находится внутри моего контроллера покоя, который возвращает список сохраненных вложений [изображения], преобразованные из файла PDF
//TODO Check mime type
when(model.extension){
// TODO all below processes are async
"pdf" -> {
list = powerPointToImageConverter.convertPdfToImages(ByteArrayInputStream(data.content), data.attachment_type!!, principal)
}
"ppt" -> {
list =powerPointToImageConverter.convertPPTToImages(ByteArrayInputStream(data.content), data.attachment_type!!,principal)
}
"pptx" -> {
list = powerPointToImageConverter.convertPPTXToImages(ByteArrayInputStream(data.content), data.attachment_type!!,principal)
}
else -> throw FileNotUploadedException()
}
if (list.get().isNotEmpty()){
(thatcourse.docs as PersistentBag).addAll(list.get())
stRepo.save(thatcourse)
}
И внутри моего Сервиса у меня есть следующая функция, которая преобразует pdf в набор изображений, сохраняет в db и возвращает результат в случае успеха
// TODO Convert PPTX into Images
@Async("asyncExecutor")
fun convertPPTXToImages(inputStream:InputStream, attachment_type: AttachmentType, principal: Principal): CompletableFuture<List<BaseFileUploaderAttachment>> {
log.info("convertPPTXToImages starts")
try{
val pptx = XMLSlideShow(inputStream)
//getting the dimensions and size of the slide
val pgsize = pptx.pageSize
val pptxSlide = Arrays.asList<XSLFSlide>(*pptx.slides)
var outputList:MutableList<BaseFileUploaderAttachment> = arrayListOf()
for (i in pptxSlide.indices) {
val img = BufferedImage(pgsize.width, pgsize.height, BufferedImage.TYPE_INT_RGB)
//render
pptxSlide[i].draw(createImage(img, pgsize))
val bytes = convertBuffToBytes(img)
val attachment = getAttachment(i,attachment_type.toString().toLowerCase().plus(Const.ST_ATTACHMENTS), attachment_type.code, bytes.size.toLong())
val filename = attachment.filename + "." + attachment.extension
val result = fileManagerService.createFile(bytes, filename, attachment.path)
if (result)
outputList.add(attachment)
//creating an image file as output
// imageFile(i, img)
}
outputList = attachmentService.saveAll(outputList, principal).toMutableList()
log.info("convertPPTXToImages completed")
return CompletableFuture.completedFuture(outputList)
}
catch (ex:Exception){
throw FileNotUploadedException()
}
}
Файл My Config для асинхронного исполнителя
@Configuration
@EnableAsync
class AsyncConfiguration {
@Bean(name = ["asyncExecutor"])
fun asyncExecutor(): Executor {
val executor = ThreadPoolTaskExecutor()
executor.corePoolSize = 3
executor.maxPoolSize = 3
executor.setQueueCapacity(100)
executor.threadNamePrefix = "AsynchThread-"
executor.initialize()
return executor
}
}
Я много тестировал, загружая файлы большого размера в небольшие. Время отклика другое, очевидно, что оно занимает больше минуты из-за продолжительного времени преобразования и большего количества страниц.
Вы можете увидеть логи трех разных запросов на скриншоте ниже
Мой вопрос заключается в том, как лучше или лучше всего подойти к этому, и что, если я хочу вставить несколько файлов pdf или pptx в цикл, например
attachments.forEach {
val entity = LearningMaterial()
var list: CompletableFuture<List<BaseFileUploaderAttachment>>? = null
var type: LearningMaterialType = LearningMaterialType.OTHER
when (it.extension) {
"pdf" -> {
list = powerPointToImageConverter.convertPdfToImages(it, principal)
type = LearningMaterialType.PRESENTATION_PDF
}
"ppt" -> {
list = powerPointToImageConverter.convertPPTToImages(it, principal)
type = LearningMaterialType.PRESENTATION_PPT
}
"pptx" -> {
list = powerPointToImageConverter.convertPPTXToImages(it, principal)
type = LearningMaterialType.PRESENTATION_PPT
}
"doc", "docx" -> {
type = LearningMaterialType.DOCUMENT_WORD
}
}
entity.mainFile = it
if (list != null)
entity.contentList.addAll(list.get())
else
entity.downloadable = true
entity.type = type.code
learningMaterials.add(entity)
}