Skip to content

Trouble Shooting

kyuhyun-sim edited this page Oct 4, 2022 · 25 revisions

@PatchMapping JPA

1. 문제상황

update 함수가 작동하지 않는 문제
해당 update문을 지날 때, response값으로는 변경된 값이 적용되나 실제도 DB상에 적용되지 않는 상황. member값이 순간동안 바뀌나 변경감지가 제대로 작동하지 않았음을 확인.

2. 시도한 방법

  1. @Dynamic을 추가하여 변경된 컬럼만 업데이트 쿼리를 날린다. update함수가 실행하지 못하는 이유가 쿼리의 문제라고 여겨 추가하였으나 변함없음 → @DYNAMIC은 단점이 많은 어노테이션으로 되도록 쓰지 않아야 한다.
  2. @Transactional을 추가하여 영속성을 유지. 다만 그럼에도 update쿼리 작동 안함
  3. memberRepository.save(member) 을 통해 저장 ⇒ update가 작동하지 않는 근본적인 원인을 해결하지 못함

3. 해결한 방법:

JPARepository를 상속받은 Repository에서 정보를 불러와야 JPA의 함수가 작동할 수 있다. 즉, request의 헤더에서 파싱한 member정보는 JPA 자체가 시동되지 못한다. 즉, JPA의 변경감지가 작동하지 않아 update함수로 인하여 member값은 일시적으로 변하고 ResponseDto에 적용이 되지만 실질적으로 DB에 적용되지 않는다. 그렇기에 JPA의 변경감지를 상속받은 리포지토리에서 불러온 member값은 update로 변환된 값이 변경감지로 인식되어 DB값도 변경되게 된다.


촬영한 사진 업로드 ( Base64 파일 )

1. 문제상황

multipartFile이 아닌 Base64파일을 S3에 업로드하게 된 상황

  • 촬영한 사진은 이미지 파일이 아닌 Base64파일로 서버로 넘어오게 된다.
  • @RequestParam으로 가져오려 했으나 Base64길이가 너무 길어 에러가 남

2. 시도한 방법

  • @RequestBody로 변경하여서 받았지만 저장되지 않음. (MultipartFile로 변환이 필요함)
  • Base64 를 File로 변환하고 File을 MultipartFile로 변환하여 시도 → contentType이 nullException이 뜨는 현상 발생
      public class Base64Util {
             public File getImageFromBase64(String base64String, String fileName) {
             String[] strings = base64String.split(",");
             String extension;
             switch (strings[0]) { // check image's extension
                   case "data:image/jpeg;base64":
                           extension = "jpeg";
                           break;
                   case "data:image/png;base64":
                           extension = "png";
                           break;
                   default: 
                           extension = "jpg";
                           break;
                     }
            byte[] data = DatatypeConverter.parseBase64Binary(strings[1]);
      File file = new File(fileName + extension);
      try (OutputStream outputStream = new BufferedOutputStream(new FileOutputStream(file))) {
              outputStream.write(data);
          } catch (IOException e) {
                   e.printStackTrace();
          }
          return file;
      }
                
      public MultipartFile convertFileToMultipartFile(File file) throws IOException {
              FileItem fileItem = new DiskFileItem("file"
                     , Files.probeContentType(file.toPath())
                     , false, file.getName()
                     , (int) file.length(),
                     file.getParentFile());
              try {
                     InputStream is = new FileInputStream(file);
                     OutputStream os = fileItem.getOutputStream();
                     IOUtils.copy(is, os);
                     } catch (IOException e) {
                           throw new IOException(e);
                     }
                     return new CommonsMultipartFile(fileItem);
               }
  • image type에서 “.”을 추가하여 확장자를 만들어줌으로서 contentType 생성 → 버킷으로 저장 완료. 하지만 file이 서버에 저장되는 현상 발생
                switch (strings[0]) { // check image's extension
                            case "data:image/jpeg;base64":
                                extension = ".jpeg";
                                break;
                            case "data:image/png;base64":
                                extension = ".png";
                                break;
                            default: // should write cases for more images types
                                extension = ".jpg";
                                break;
}
  • 서버에 저장되는 사진을 삭제하는 로직을 추가→ 사진이 삭제 되지 않음
        private void removeNewFile(File targetFile) {
            if(targetFile.delete()) {
            log.info("파일이 삭제되었습니다.");
            }else {
                log.info("파일이 삭제되지 못했습니다.");
            }
        }
  • 서버에 사진을 저장하지 않기 위해 S3Uploader에서 바로 Base64파일을 업로드하는 로직 구현 → 버킷에 확장자 명이 안나타나는 문제 발생
                public String getImgUrlBase64(String base64){
                            String[] strings = base64.split(",");
                            String extension = switch (strings[0]) {
                                case "data:image/jpeg;base64" -> ".jpeg";
                                case "data:image/png;base64" -> ".png";
                                default -> // should write cases for more images types
                                        ".jpg";
                            };
                        byte[] data = DatatypeConverter.parseBase64Binary(strings[1]);
                        long now = new Date().getTime();
                        String fileName = UUID.randomUUID().toString() + now;
                        InputStream img = new ByteArrayInputStream(data);
                        ObjectMetadata metadata = new ObjectMetadata();
                        amazonS3Client.putObject(new PutObjectRequest(bucket, fileName, img, metadata)
                                .withCannedAcl(CannedAccessControlList.PublicRead));
                        return amazonS3Client.getUrl(bucket, fileName).toString();
                    }
  • fileName에 extention을 추가함 → 저장된 사진이 바로 다운로드가 되는 현상 발견 (버킷에 업로드 할 때 콘텐트 타입이 저장되지 않으면 형식을 알 수없어 바로 다운로드가 된다는 사실을 발견)
                        byte[] data = DatatypeConverter.parseBase64Binary(strings[1]);
                        long now = new Date().getTime();
                        String fileName = UUID.randomUUID().toString() + now + extension;
                        metadata.setContentType("image/"+extension.substring(1));
                        metadata.setCacheControl("public, max-age=31536000");
                        amazonS3Client.putObject(new PutObjectRequest(bucket, fileName, img, metadata)
                                .withCannedAcl(CannedAccessControlList.PublicRead));
                        return amazonS3Client.getUrl(bucket, fileName).toString();
                    }
  • ObjectMetadata에 콘텐트 타입과 길이 증을 설정. → 버킷에 정상 저장.
                        byte[] data = DatatypeConverter.parseBase64Binary(strings[1]);
                        long now = new Date().getTime();
                        String fileName = UUID.randomUUID().toString() + now + extension;
                        InputStream img = new ByteArrayInputStream(data);
                        ObjectMetadata metadata = new ObjectMetadata();
                        metadata.setContentLength(data.length);
                        metadata.setContentType("image/"+extension.substring(1));
                        metadata.setCacheControl("public, max-age=31536000");
                        amazonS3Client.putObject(new PutObjectRequest(bucket, fileName, img, metadata)
                                .withCannedAcl(CannedAccessControlList.PublicRead));
                        return amazonS3Client.getUrl(bucket, fileName).toString();
                    }

3. 해결한 방법

  • S3에 Base64를 바로 업로드 하여 서버에 파일 저장 방지
  • S3 업로드 시 contentType을 반드시 설정하여 다운로드가 되지 않도록 수정

@RequestBody에서 스트링 값만 받아오는 경우

1. 문제상황

@RequestBody에 있는 값이 제대로 들어가지 않음

  • postman으로 body에 String값을 그냥 써넣으면 제대로 들어가지만 json으로 받으면 받아지지 않는다.
  • Body내에 있는 문자열을 모두 받아오는 현상 발생.

2. 시도한 방법:

  • 문자열만 전송하자 위와같이 이상한 문자열로 변환됨
  • Map{String,String} 을 사용하여 값을 받음
  • 할 수 있는 방법: requestDto를 사용하여 매핑을 해주는 방식

3. 해결한 방법: Map<String,String> 을 사용하여 값을 받음


이미지 리사이징

1. 문제상황

이미지 리사이징 로직이 작동하지 않음

2. 시도한 방법

  • 콘솔로 찍어보니 imageIcon에서 getWidth, getHeight 값이 -1로 찍히는 것을 확인

  • 길이와 넓이가 잘 나오지만 비율이 맞춰지지 않는 것을 확인

  • 추가한 코드

                publicImageSizeDtodefineSize(intheight, intwidth) {
                    if (height>width) {
                        double ratio = (double)width/ 320;
                        int resizedHeight = (int) (height/ ratio);
                        log.info(height+"     "+width);
                        return (new ImageSizeDto(resizedHeight, 320));
                    }
                    int ratio =height/ 320;
                    int resizedWidth =width/ ratio;
                    log.info(height+"     "+width);
                    return (new ImageSizeDto(320, resizedWidth));
                }
  • BufferedImage로 변환시 null이 뜨는 오류
  • 시도한 코드
                           Image resizedImage = image.getScaledInstance(sizeDto.getWidth(), sizeDto.getHeight(), Image.SCALE_SMOOTH);
                           ImageInputStream resizedImageInputStream = ImageIO.createImageInputStream(resizedImage);
  • SdkClientException:Data read has a different length than the expected
  • 시도한 코드
                IOUtils.toByteArray(resizedImg).length
  • 시도한 코드
                resizedImg.readAllBytes().length
  • 리사이징 된 이미지 data 0 bite
  • 시도한 코드
                log.info("이미지 : "+ width + "   " + height);
                        BufferedImage outputImage = new BufferedImage(sizeDto.getWidth(), sizeDto.getHeight(), inputImage.getType());
                        log.info("이미지 : " + sizeDto.getHeight() + "   " + sizeDto.getWidth());
                        Graphics graphics2D = outputImage.getGraphics();
                        graphics2D.drawImage(resizedImage, 0, 0, null); // 그리기
                        graphics2D.dispose(); // 자원해제
                
                        ByteArrayOutputStream os = new ByteArrayOutputStream();
                        ImageIO.write(outputImage, "png", os);
                        log.info("이미지 DONE");
                        return new ByteArrayInputStream(os.toByteArray());

3. 해결한 방법

  • 해결한 코드
            publicStringgetImgUrlBase64(Stringbase64) throwsIOException{
            String[] strings =base64.split(",");
            Stringextension = switch (strings[0]) {// check image's extension
            case "data:image/jpeg;base64" -> ".jpeg";
                        case "data:image/png;base64" -> ".png";
                        case "data:image/webp;base64" -> ".webp";
                        default -> ".jpg";
                    };
                    byte[] data =DatatypeConverter.parseBase64Binary(strings[1]);
            
                    InputStream imgStream = new ByteArrayInputStream(data);
                    InputStream resizedImg = checkImage(imgStream);
            
            ObjectMetadatametadata = new ObjectMetadata();
                    metadata.setContentLength(resizedImg.available());
                    metadata.setContentType("image/" + extension.substring(1));
                    metadata.setCacheControl("public, max-age=31536000");
            
                    long now = new Date().getTime();
                    StringfileName = now + "_" +UUID.randomUUID() + extension;
                    amazonS3Client.putObject(new PutObjectRequest(bucket, fileName, resizedImg, metadata)
                            .withCannedAcl(CannedAccessControlList.PublicRead));
                    return amazonS3Client.getUrl(bucket, fileName).toString();
                }
            
                public InputStream checkImage(InputStreamimgStream) throwsIOException{
            BufferedImageinputImage =ImageIO.read(imgStream);
                    int imageHeight = inputImage.getHeight(null);
                    int imageWidth = inputImage.getWidth(null);
                    if (imageHeight > 320 && imageWidth > 320) return resize(inputImage, imageWidth, imageHeight);
                    else {
            ByteArrayOutputStreamoutStream = new ByteArrayOutputStream();
            ImageIO.write(inputImage,"png",outStream);
                        return new ByteArrayInputStream(outStream.toByteArray());
                    }
                }
            /*리사이즈 실행 메소드 */
            public InputStream resize(BufferedImageinputImage, intwidth, intheight) throwsIOException{
            
            ImageSizeDtosizeDto = defineSize(height,width);
                    Image resizedImage =inputImage.getScaledInstance(sizeDto.getWidth(),sizeDto.getHeight(),Image.SCALE_SMOOTH);
            
            BufferedImageoutputImage = new BufferedImage(sizeDto.getWidth(), sizeDto.getHeight(),inputImage.getType());
            
                    Graphics graphics2D = outputImage.getGraphics();
                    graphics2D.drawImage(resizedImage, 0, 0, null);//그리기
            graphics2D.dispose();//자원해제
            
            ByteArrayOutputStreamos = new ByteArrayOutputStream();
            ImageIO.write(outputImage, "png", os);
                    return new ByteArrayInputStream(os.toByteArray());
                }
            
            publicImageSizeDtodefineSize(intheight, intwidth) {
                    if (height>width) {
                        double ratio = (double)width/ 320;
                        int resizedHeight = (int) (height/ ratio);
                        return (new ImageSizeDto(resizedHeight, 320));
                    }
                    int ratio =height/ 320;
                    int resizedWidth =width/ ratio;
                    return (new ImageSizeDto(320, resizedWidth));
            }

깃 액션을 이용한 빌드 실패

1. 문제상황

서버 자동 배포 과정 중 깃 액션을 이용한 main 브랜치 레포지토리 빌드 과정이 실패함

2. 시도한 방법

  • 원인을 확인해보니 properties 파일이 ignore 처리 되어 있어서 깃 허브 레포지토리에 존재하지 않는 것을 발견
  • 기존 deploy.yml 파일에 존재하는 깃 액션 과정에 properties 파일을 생성하는 과정을 추가하기로 함

3. 해결한 방법

  • 해결한 코드
      - name: make application.properties
        run:
          touch ./src/main/resources/application.properties 
        shell: bash
        
      - name: deliver application.properties
        run: 
          echo "${{ secrets.PROPERTIES }}" > ./src/main/resources/application.properties
        shell: bash
  • Settings>Secret>Actions 이동 후 NEW REPOSITORY CREATE 를 클릭하여 PROPERTIES 파일을 생성.
  • 파일안에 값은 이그노어 처리했던 application.properties 파일안의 값을 그대로 넣어줌.

ACM 인증서 발급이 계속해서 지연되는 문제

1. 문제상황

Https 배포를 위한 과정 중 하나인 ACM 인증서 발급이 계속해서 지연됨

2. 시도한 방법

  • 기존에 시도한 CNAME 레코드를 이용한 ACM 발급 방법 대신 이메일 인증을 통한 ACM 발급을 시도함 -> 발급되지 않음
  • CNAME 레코드를 통해 연결된 호스팅 영역의 NS 레코드 값과 구매한 도메인의 NS 레코드 값이 일치 하지 않는 것을 발견

3. 해결한 방법

  • 호스팅 영역의 NS 레코드 값으로 구매한 도메인의 NS 레코드 값을 변경해줌
  • 다시 ACM 인증서 발급 재시도
  • 1분만에 ACM 인증서가 재발급 된 것을 확인함

Code Deploy를 이용한 서버 배포 실패

1. 문제상황

Code Deploy를 이용한 Https 서버 배포 시도 중 AllowTraffic 단계에서 실패 발생

2. 시도한 방법

  • 찾아보니 health checker 에러일 확률이 높다고 함
  • 로드 밸런서를 적용하던 과정 중 생성하였던 태그 그룹을 확인
  • health checker(상태 검사) 부분에서 계속 실패하는 것을 확인
  • 상태검사 포트를 HTTP 에서 HTTPS 로 변경 하고 재시도 -> 여전히 해결되지 않음
  • 서버의 경우 클라이언트와 달리 정상 배포 시 성공 코드는 200이 아닌 404라고 함

3. 해결한 방법

  • health checker success code의 설정 값을 200에서 404로 변경해 줌
  • health checker 가 정상으로 변경된 것을 확인
  • Code Deploy를 이용한 서버 배포 과정 모두 성공

Code Deploy를 이용한 서버 배포 과정이 매우 느리게 진행되는 문제

1. 문제상황

Code Deploy를 이용한 Https 서버 배포 시 최소 6분이상 시간이 소모되는 문제가 발생

2. 시도한 방법

  • Code Deploy의 view 이벤트를 확인해 보니 AllowTraffic 단계에서 5분 이상의 시간이 지체되는 것을 확인
  • health checker 과정을 수행하는데 많은 시간이 소요되는 것으로 보임
  • health checker 설정을 변경해 보기로 함

3. 해결한 방법

  • 타겟 그룹 attribute 시간 설정을 default 값인 300초에서 30초로 변경해 줌
  • AllowTraffic 단계에서 소요되는 시간이 30초대로 단축
  • 서버 배포 속도가 2분 내외로 단축되는 것을 확인

Clone this wiki locally