1. 어려웠던 부분 

  • 오늘 드디어 프론트엔드 팀원분과 그동안 작성하고 기다리고 있던 리프레시토큰을 적용해보았다. 분명히 나는 헤더에 엑세스토큰과 리프레시토큰을 보냈는데, 쿠키엔 undifined 라고 떠서 어디서 막힌걸까 헤맸는데, 지나가는 시넌님이 개발자창의 Network tap을 활용하는 법을 알려주셨다. 네트워크탭을 확인해보니 다행히 백에서는 response header에 토큰을 잘 담아 보내주고 있었다. 프론트에서 쿠키에 set하는 과정에서 오류가 있었는데 이 부분을 수정한 뒤 잘 반영이 되었다. 비록 길을 잃어 삽질하느라 9시간이나 걸렸지만, 그래도 오늘 안에 나의 밀린 과제였던 리프레시 토큰을 해결해서 다행이다! 

 

2. 느낀 점 : 

  • 백엔드는 보통 디버깅을 할 때 log를 찍거나 디버깅을 하는데, 프론트단에서는 consol을 찍거나 개발자 창을 통해 확인을 한다. 개발자도구 inspect는 진짜 디버깅할 때 유용한 것 같다! 리엑트 코드를 나도 좀 더 이해할 수 있으면 작업이 정말 편할 것 같다. 언젠가 리액드를 공부해 보기로...! 

 

3. 새로 알게 된 내용 :

  • 블로그 글과 구글링을 통해 리프레시 토큰을 구현했다. 글들에 설명이 부족해서 처음에 도대체 토큰 재발급 api요청은 언제 어떤 방식으로 보내야 하는지 엄청 헤맸다.
  • 첫 시도는 사용자가 토큰 만료후 어떠한 요청을 보냈을 때 토큰만료 Status Code를 401번으로 서버에서 프론트로 응답했는데, 이 401 코드가 뜨면 프론트에서 해당 토큰재발급 api 요청을 보내는 것으로 설계했다. 그러나 어떤 이유에서 401번 코드가 먹히지가 않았다. 
  • 다음 방법은 현재 갖고 있는 액세스 토큰 만료시간 5분 전에 setTimeout()을 활용해서 요청을 보내는 것으로 수정했더니 정상 작동 하였다. 아래는 프론트에서 만료시간 전 토큰 재발행 요청을 하는 코드 일부분이다.
export const setAccessToken = (token) => {
  const expireDate = new Date();
  expireDate.setMinutes(expireDate.getMinutes() + 30);

  setTimeout(() => {
    instance.post('/auth/issue/token').then((response) => {
      setAccessToken(response.headers.accesstoken);
    });
  }, 25 * 60 * 1000);

  cookies.set(ACCESS_TOKEN, token, {
    path: '/',
    expires: expireDate,
  });
};

 

4. 셀프칭찬 (오늘 잘한 일) 

  • 항상 내가 할 수 있을까? 라는 생각으로 의심하고 걱정했는데, 그래도 오늘 리프레시 토큰이라는 과제를 끝내서 다행이라고 생각했다! 

5. 내일 할 일 : 버그수정, 토요일 멘토링 준비 ( 개념 공부 )

 

 

1. 어려웠던 부분 

  • 오늘 드디어 서비스 배포를 했다. 그런데 배포하자마자 엄청난 오류가 발생했다. 게임룸에서 나와도 웹소켓이 제대로 끊기지 않아서 콘솔창으로 확인했을 때 계속해서 채팅내용이 보이고, 또 게임방에 입장했을 때 갑자기 2개 3개로 입장이 되는 등.. 배포하자마자 오류를 발견해서 허겁지겁 고치기 시작했다.
  • 원인은 프론트단에서 웹소켓을 끊어주는 코드가 빠져있었다. 아래의 코드를 추가하고 에러 해결! 휴 진땀 났던 몇 시간 ;;
        .delete(`rooms/${param.roomId}/exit`)
        .then(async (res) => {
          socketRef.current.close();
          console.log('클라이언트', client.current);
          client.current.deactivate(); // 이 부분 추가
        })
        .catch(async (error) => {
          socketRef.current.close();
          client.current.deactivate(); // 이 부분 추가
        });
    };
  }, []);

 

2. 느낀 점 :  끝날때까지 끝난 게 아님

 

3. 새로 알게 된 내용 

  • 오늘 받은 피드백 중 콘솔 창에 찍히는 로그를 지워야 한다는 피드백이 있었다. 이제 개발 부분은 서서히 끝나다보니 보안 부분을 더 신경쓰게 되었다. 콘솔에 찍히는 로그도 지워주고, S3 엔드포인트를 가려주기도 하고, 또 토큰을 어디다 저장할지도 생각해보게 되고 하나가 끝났다고 끝난게 아니라 계속해서 버그를 찾고 발전시켜야 하는 코딩의 세계 ~_~

 

4. 셀프칭찬 (오늘 잘한 일) 

  • 오늘도 트러블슈팅으로 하나 더 배웠다 !

 

5. 내일 할 일 : 유저 피드백 반영해서 자잘한 버그 수정하기 ! 

 

 

1. 어려웠던 부분 

  • 오늘은 이런 저런 테스트를 하면서 자잘한 오류를 잡으면서 하루를 보냈다. 너무 사소한 오류들이라서 생각도 나지 않는다~_~ 피곤하다. 서비스 배포를 앞두고 구글 설문지 폼을 작성하고, 대외용 노션 페이지도 만들고, 홍보용 이미지와 카피라이터를 준비했다. 개발만 신경쓸게 아니라 서비스 하나를 만드는데 이것 저것 참 신경써야 할 부분이 많다.

 

2. 느낀 점 : 

  • 프로젝트 하나를 통해 정말 다양한 경험을 하는 것 같다. 기획부터 개발, 서비스 런칭 전 마케팅 준비까지. 덕분에 내가 어느 부분에서 더 흥미를 느끼고 잘 하는지 알게된 것 같다 : ) 

 

3. 새로 알게 된 내용 :

  • 구글 설문 폼 만드는 방법 (완전 쉬움 ! 아래 링크를 이용하기)

https://www.google.com/intl/ko_kr/forms/about/

 

Google Docs

Google Docs. 좋아하는 사람 57,329명 · 이야기하고 있는 사람들 262명. News and updates about Google Docs, Sheets, Slides, Sites, Forms, and more!

www.facebook.com

 

4. 셀프칭찬 (오늘 잘한 일) 

  • 지난 크리스마스도, 새해도, 설날도 그리고 오늘 내 생일도 항해99를 하며 보냈다. 이 시기가 지나고 나면 개발자가 되지 못하더라도 후회는 없을 것 같다. 마지막까지 후회 없이 잘 버티고 열심히 공부하자 ! 

 

5. 내일 할 일 : 드디어 서비스 배포 ! 

 

 

우리조 홧띵

 

 

 

1. 어려웠던 부분 

  • 현재 코드에서는 게시글에 이미지를 업로드하면 S3 버켓 주소가 이미지 url 주소에 그대로 노출되고 있었다. 시니어 개발자님이 이 엔드포인트 부분을 그대로 노출시키면 안된다는 피드백을 주셔서 오늘은 팀원들과 그 부분을 수정하는 작업을 했다. 
  • 일단 우리 코드에서 변경된 부분은 아래와 같다.

아래는 수정된 코드 부분 ( 주소 처리 )

    private String upload(File uploadFile, String dirName) { // dirName이란 S3에 생성된 디렉토리
        String fileName = dirName + "/" + UUID.randomUUID(); // 파일 이름(디렉토리명 + / + 랜덤 + 파일명)
        putS3(uploadFile, fileName);
        String newUrl = "https://" + bucket + "/" + fileName;
        removeNewFile(uploadFile); // 로컬에 생성된 File 삭제
        return newUrl; // 업로드된 파일의 S3 URL 주소 반환
    }

 

  • 그 외의 작업은 모두 AWS 에서 이루어 진다. 서브 도메인에 버켓주소를 추가해주고, 대체 도메인 주소를 설정해서 가려주었다.
  • AWS에서의 처리 과정 : 서브 도메인 만들고 -> 서브 도메인 이름과 버켓 이름을 같게 맞춰준다(Route 53) -> S3 버켓에서 정적  웹사이트 호스팅 활성화 시켜주기 -> Cloud Front 에서 원본이미지 (엔드포인트가 나와있는) 주소 대신 대체 도메인 이름을 설정 ! 

 

 

 

2. 느낀 점 : 

  • 시니어 개발자님의 피드백을 받을때마다 생각지도 못한 놓쳤던 부분을 많이 알게 된다. 예전엔 개발자라 하면 그저 무뚝뚝한 이미지가 떠올랐는데 이젠 엄청 세심한 이미지가 떠오른다. 코딩의 세계는 정말 어렵다 ! 

 

3. 새로 알게 된 내용 :

  • 보안은 정말 중요하다! S3 버켓 엔드포인트가 노출되지 않도록 하자! 

 

4. 셀프칭찬 (오늘 잘한 일) 

  • 오늘도 느리지만 또 한가지 배우고 성장했다 ! 난 느리지만 잘 하고 있다 ! 

 

5. 내일 할 일 : 배포 전 테스트 / 버그 잡기


[오늘 공부한 부분] 

 

[ 참고 자료 ]

 

서버리스 서비스 예제 - 04 [S3 정적 웹사이트에 https 적용하기]

S3에 생성한 정적 웹사이트는 http로 만들어진 endpoint로 접속이 가능합니다. 사용자들의 보다 안전한 접속을 보장하기 위해 https를 적용하는 방법을 알아보겠습니다. 여담인데 S3에 있는 각각의 파

ongamedev.tistory.com

 

 

AWS - S3, CloudFront, Route53을 이용한 정적 호스팅

내가 만든 웹을 다른 사람들이 볼 수 있도록 하려면 배포과정이 필요하다.AWS는 S3라는 저장소를 제공하는데 저렴한 비용으로 정적 호스팅을 할 수 있다는 장점이 있다.하지만 S3에서 기본적으로

velog.io

 

 

 

 

 

1. 이번주 트러블 슈팅 :

  • 시그널링 서버 연결 시에 sendMessage() 메소드가 동시적으로 작동했을 때 소켓 연결이 끊어지는 이슈가 있었는데, 이를 synchronized 를 활용해서 순차적으로 진행될 수 있도록 변경.
  • 서비스 로직 정상 작동 확인 후 해당 서비스 로직에 다른 서비스 로직을 끼워넣었을 때, 끼워 넣은 서비스 로직이 실행되는 않는 이슈 발생 → 끼워넣은 서비스 로직에서 데이터를 삭제하는 로직이 포함되어 있어서 첫 서비스 로직에서 @Transactional 을 붙여준 뒤 해결
  • 리프레쉬 토큰 사용을 위한 Redis 데이터 베이스에서 TTL을 걸어두었지만 시간이 지나도 DB에서 삭제되지 않는 것으로 확인 → Redis에서 만료 시간을 설정하는 방법은 RedisTemplate 오퍼레이션 사용시 만료 시간을 설정하는 법과 CrudRepository를 이용하여 저장할 객체에 timeToLive를 설정하는 방법 두 가지가 있는데, RedisTemplate만을 이용하면서 객체에 timeToLive를 적용해 제대로 적용되지 않음. 제대로 적용할 수 있게 CrudRepository를 사용해 timeToLive가 적용될 수 있도록 해결
  • 게시판 이미지 S3에 업로드 후 저장 경로가 서비스 도메인과 동일하게 시작 → SSL 인증이 안 되기 때문에 프론트에서 이미지를 보여줄 수 없음 → S3 버킷 이름을 변경하여 해결
  • 뒤로가기 버튼이 아닌 인터넷 브라우저 탭 강제 종료 시 데이터가 변하지 않는 상황 발생 → WebRTC 연결 끊기는 로직에 게임 강제 종료 로직 추가

2. 프로젝트에 새롭게 도입한 기술 : 

  • CI/CD 자동화 배포
    • github action을 통해 CI를 거친 빌드 파일이 S3에 저장된 다음 AWS CodeDeploy에 의해 EC2에 배포됩니다.
    • 도입 이유 : 자동 테스트, 빌드, 배포를 통해 개발자가 더 편리하게 개발에만 집중 할 수 있도록 해줍니다.
  • 동시성 제어
    • 비관적 락을 통한 DB제어와 synchronized를 활용한 session 동시성 제어 적용
    • DB 제어 도입 이유: 한방에 동시 입장시 동일한 데이터에 대한 수정 요청이 발생해 데이터 일관성에 문제가 생길 것이라 생각해 이를 방지하기 위해 락을 설정했습니다.
    • 세션 제어 도입 이유: 시그널링 서버에 여러 명이 동시에 접속 시 Websocketsession 충돌로 연결이 끊기는 이슈를 해결하기 위해 도입했습니다. session에서 sendMessage는 동시 전송이 불가능하여 이를 차례대로 처리할 수 있도록 해당 메소드에 synchronized를 적용했습니다.

 

3. 이번주 한 일 :

  • CI/CD (Github Actions, AWS CodeDeploy)
  • 방 입장하기 동시성 제어
  • 와일드 카드 또는 제네릭 형태의 return 값 구체화
  • 커뮤니티 게시판 API
  • 시그널링 서버 메세지 발송 메소드 동시성 제어
  • S3 이미지 업로드 기능 구현
  • Refresh 토큰 구현 중 (FE와 맞춰봐야 함)
  • GameStartSet DB Redis에서 MySQL로 변경
  • DB 관련 로직 RepositoryService로 분류하여 리팩토링
  • HashMap 타입 일괄 Map으로 수정 (추후 유지보수를 위해 상위 클래스인 Map으로 수정)
  • GameService와 GameRearService 관심사에 맞게 통합 운영 (리팩토링)
  • 게임 키워드 추가
  • 추후 마케팅 작업을 위한 유저 별 방 생성 횟수, 플레이타임 등 Column값 추가 및 로직 구현

 

4. 궁금했던 부분 

  • 현재 synchronized 로 동시성을 제어하는 것이 굉장히 느리다고 알고 있는데, Spring 공식 문서에서 메세지 전송을 동기화 하기 위해서 ConcurrentWebSocketSessionDecorator 도 제공하고 있다고 해서 두 가지 중에 고민입니다. 
    • 일단 웹소켓을 못가져오는 이유를 먼저 찾아보고 그래도 모르겠으면
    • 일단 Concurr ~ 먼저 적용 , 그래도 안되면 Synchronized 사용 .
    • 최대한 싱크로나이즈드는 지양하는게 좋다. 성능이 너무 안좋음.
  • Controller 단에서 ResponseEntity<?>와 같이 반환 데이터 타입을 명시적으로 정해주지 않고 사용했었는데, Front로 내보내는 반환 값으로 와일드카드를 쓴다는 건 반환하는 메소드에서 의도한 타입으로 나가든, 의도하지 않은 타입으로 나가든 성공적으로 나가게 되는거 같습니다. 내보내는 반환 값을 명확하게 설정해주면 잘못된 타입으로 나가는 걸 방지해줄 수 있기 때문에 명시적으로 사용하는 거 같은데 옳게 이해한 걸까요? -
    • 옵션 1. 하이브리드 방식
    • ? extends Object - 이런식으로 쓸 수 있다. 특정 클래스의 하위클래스만 내보내는 방법이기도 하다
    • 옵션 2. ? 그대로 사용 - 문제는 없음.
  • 현재 메세지 브로커를 STOMP 내장 브로커를 활용하고 있는데, 스케일아웃을 했을 때 동작하지 않는 것으로 알고있습니다. 만약의 상황에서 서버를 스케일아웃을 했을 때 정상작동하도록 메세지 브로커로 Redis나 RabbitMQ를 사용하는 것이 나을까요?
    • 현재 메시지브로커 역할을 하는지? 멘토님이 알기론 아님.
    • 브로커 입장에서는 이미 바라보고 있는 데이터가 스케일 아웃을 하던 안하던 상관없다.
    • 인스턴스 객체가 인메모리상에 뜨는데 얘가 다른 인스턴스의 스톰프를 알아야되는 상황이 맞는지 ?
    • 그게 아니라면 굳이 외부메시지브로커를 사용할 필요가 없다.

 

5. 다음주 할 일 : 서비스 배포 !!

+ Recent posts