Как сделать так, чтобы файловая часть Spring WebFlux выполнялась асинхронно?

#java #spring-webflux

Вопрос:

Я загружаю файлы в S3 с помощью Spring WebFlux, ниже приведен мой код

FileController.java

 public Mono<UploadResponse> upload(@RequestPart("file") Mono<FilePart> partMono) {
    return partMono
        .doOnNext(filePart -> log.info("Received File : "   filePart.filename()))
        .flatMap(filePart -> fileService.uploadFile(filePart));
  }
 

FileService.java

 public Mono<UploadResponse> uploadFile(FilePart filePart) {
    try {
      log.info("Thread in ImageService: {}", Thread.currentThread().getName());e
      String fileName = filePart.filename();
      var fileUrl = fileRepository.getUrl(fileName);
      var targetFile = File.createTempFile(filePart.filename(), "");
      return filePart.transferTo(targetFile)
      .doOnSuccess(x -> {
        log.info("Thread in Mono: {}", Thread.currentThread().getName());
        fileRepository.uploadFile(targetFile, fileName);
        log.info("Delete file {}", targetFile.getAbsolutePath());
        targetFile.delete();
      })
      .thenReturn(UploadResponse.builder()
          .fileName(fileName)
          .url(fileUrl)
          .build());
    } catch (Exception e) {
      log.error(e.getMessage(), e);
      throw new FileUploadException("File upload fail. Reason: "   e.getMessage(), e);
    }
  }
 

S3FileRepository.java

 public UploadResponse uploadFile(File file, String fileName) {
    log.info("Uploading {} to S3 bucket {}...", fileName, bucketName);
    try {
      var fileUrl = s3Client.getUrl(bucketName, fileName).toExternalForm();
      var request = new PutObjectRequest(bucketName, fileName, file);
      if(cannedAcl != null) {
        request.withCannedAcl(cannedAcl);
      }
      s3Client.putObject(new PutObjectRequest(bucketName, fileName, file));
      var response = UploadResponse.builder()
          .fileName(fileName)
          .url(fileUrl)
          .build();

      return response;
    } catch (AmazonServiceException e) {
      log.error("Upload of {}  to S3 bucket {} FAILED", fileName, bucketName);
      throw e;
    }
  }

  public String getUrl(String fileName) {
    return s3Client.getUrl("mybucket", fileName).toExternalForm();
  }
 

В методе загрузки файловой службы я не вызываю никаких методов подписки на файловую часть, но он все равно запускается и вызывает метод FileRepository, почему это работает? И со стороны клиента мне нужно немного подождать, чтобы получить результат, как сделать мою загрузку полностью асинхронной и немедленно вернуть результат?

Комментарии:

1. где fileRepository.getUrl код? а также File.createTempFile является blocking вызовом. Все файловые операции блокируются.

2. что я должен сделать, чтобы избежать блокировки кода?

3. Погуглите или прочитайте справочную документацию по реактору.