개발

0. 들어가기 전에 앞선 글에서 TaskScheduler 사용한 기능을 만들었다. 그중 WAS가 많아지면 생길 Race Condition 때문에 비관적 락을 적용했다. 이 부분을 테스트하기 위해 고민한 글입니다. 1. 어떻게 테스트 할까? 동시 요청을 테스트하려면 어떻게 할 수 있을까? 이를 위한 클래스가 자바에 있다. 바로 ExecutorService다. ExecutorService는 쓰레드 풀을 만들어 비동기적으로 동작하는 것을 돕는 클래스이다. 자세한 방법은 코드로 알아보자. @DisplayName("다수의 스케줄이 동시에 실행되도 ReviewCount는 1개만 증가한다.") @Test void finishReview_when_multiple_request() throws InterruptedExc..
0. 들어가기 전에 TaskScheduler를 활용해 자동적으로 리뷰 완료 상태로 변경하는 기능을 만들었습니다. 1. 필요한 이유 리뷰 랭킹을 구현하고 나니, 리뷰했지만 리뷰 완료 버튼을 누르지 않은 리뷰어들이 많았다. 글 상태가 리뷰 진행중이라고 되어있고, 리뷰 개수가 증가하지 않아 랭킹에 못 들어간 리뷰어들이 많았다! 또한, 리뷰어 평가도 이루어지지 않았다. 이 문제를 해결하기 위해 회의를 한 결과 리뷰 진행 중이면서 마감 기한이 지나면 3일 뒤에 자동으로 리뷰 완료 상태로 변경되도록 정책을 변경하기로 했다. 2. 구현 아이디어 그럼 어떻게 구현해야 할까? 가장 먼저 생각나는 건 아래처럼 스케줄러를 사용해서, 1분마다 조건에 맞는 게시글을 찾아 상태를 바꿔주는 것이다. @Scheduled(cron =..
0. 들어가기 전에 Redis를 도입하면서 테스트 방법이 필요했는데 이에 대해 고민한 글입니다. 1. Redis 테스트는 어떻게 해야할까? Reids를 도입하면서 테스트를 어떻게 해야할지에 대한 고민이 생겼다. 기존에는 MySQL 대신에 embeded h2를 사용해서 테스트를 했다. 하지만 redis를 도입하면서 이 방법은 사용할 수 없게 되었다. 찾아보니 레디스를 로컬에서 테스트하는 방법은 두 가지 방법이 있었다. 1.1 Embedded Redis //spring-data-redis compile('org.springframework.boot:spring-boot-starter-data-redis') //embedded-redis compile group: 'it.ozimov', name: 'embed..
0. 들어가기 전에 RefreshToken을 처음 개발할 때 MySQL로 관리했는데, 시간적 여유가 생겨 Redis를 적용하는 방향을 고려해봤습니다. 1. 기존 RefreshToken의 문제점 우리 바톤팀은 Jwt를 사용해서 로그인 기능을 구현했다. Jwt를 사용해서 서버의 부담을 줄이는 것은 좋았지만, AccessToken이 만료되었을 때 로그인이 풀리는 현상이 있었다. 이 문제를 해결하기 위해 RefreshToken을 도입했다. 그때는 기능 개발할 게 많아 MySQL을 통해 RefreshToken을 관리했었다. 이러다 보니 Jwt의 장점이 무색해졌다. 세션과 달리 Jwt는 서버가 무 상태이기 때문에 대량의 요청을 받았을 때 성능이 더 좋다. 하지만 로그인이 풀린다는 Jwt의 문제점을 해결하고자 도입한..
0. 들어가기 전에 예전에 진행하던 프로젝트를 유지보수하던 중에 CORS 정책이 wildcard로 열려있는 것을 확인해 보안을 위해서 wildcard를 없애던 중 마주쳤던 문제입니다. 1. AS-IS @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") .allowedOrigins("*"); } 기존 Cors관련 메서드는 이런 식으로 와일드 카드로 열려있었다. 와일드 카드는 보안 상 안좋기도 하고 나중에 쿠키를 사용하려면 변경해야하기 때문에 이번 기회에 아래처럼 변경해보기로 했다. @Override public void addCorsMappings(CorsRegistry registry) { reg..
0. 들어가기 전에 추석 연휴 동안 우리 프로젝트의 db가 다운이 되었다.) 다운된 시점 근처에서 해외에서 악의적 요청을 보낸 로그가 있어서 마음을 졸였다. 다행이도 별 문제는 없었지만, DB가 하나인 상황이라 DB가 죽으면 서비스를 운영할 수 없다. 따라서 SPOF문제를 해결하기 위해 replication을 적용하기로 했다. 1. Replication 이란? 하나의 DB 서버를 다른 DB로 복제 하는 것 Replication은 하나의 DB 서버를 다른 서버로 데이터를 동기화하는 것을 의미한다. 예전에는 원본 데이터 서버 - 복제된 데이터 서버의 관계를 마스터(Master) - 슬레이브(Slave)라고 했지만 최근에는 소스(Source) - 레플리카(Replica)라고 말하는 추세이다. 소스 서버에서 데..
build 할 때 RestDocs 파일이 생성이 안되는 문제 트러블 슈팅 0. 들어가기 전에 저희 프로젝트는 RESTDocs를 파일을 만들어서 API를 문서화를 했습니다. 각각의 API를 종류에 맞게 adoc 파일로 관리를 해 유지보수를 하기 쉽게 사용하고 있었습니다. 하지만 이 방식의 단점은 한눈에 어떤 종류의 API가 있는지 파악하기가 어려웠습니다. 그래서 만들어진 adoc 파일을 하나의 파일로 만들 수 있는 gradle task를 만들어 사용했습니다(참고 PR). 하지만 이 과정에서 문제가 발생했는데, 이 글은 그 문제를 어떻게 해결했는지에 대해서 설명하는 글입니다. 1. 문제 상황 먼저 intellij에서 spring boot를 실행시키면 gradle에 작성한 task 대로 정상 작동합니다. ta..
[Nginx] 하나의 EC2 안에서 React와 Spring 통신하기 0. 들어가기 전에 바톤 팀의 배포 EC2는 위 그림과 같았습니다. 한 EC2 안에 react와 spring이 띄워져 있으니 localhost로 API 요청을 보내면 좋겠다고 생각했습니다. 왜냐하면 현재 EC2 인스턴스가 EIP를 받지 않은 상태이기 때문에 불의의 사고로 인해 EC2가 재부팅되면 IP가 변경되기 때문입니다. IP가 변경되면 그에 해당하는 react의 코드를 수정해야 하니 불편한 상황이 생길 것 같았습니다. 그래서 프론트엔드 크루분들께 'localhost로 요청하는 게 좋을 것 같다'고 하며 수정을 요청했습니다. 하지만 실제로 배포된 코드를 살펴보니 문제가 생겼습니다. 이 글은 이때..
쿠엔크
'개발' 카테고리의 글 목록