Spring

트러블 슈팅, 경험 기술
· Spring
필자가 운영중인 '개발 한 스푼'에서는 특정 시간에 모든 유저를 대상으로 푸시알림을 보내고 있다. 많은 양은 아니지만 알림처리를 위해 Spring Batch를 사용하고 있다. 하지만 특정 시간대에 몇 번, 몇 분 실행되는 Spring Batch를 위해 컴퓨팅 파워를 추가로 사용하는건 비용 낭비다. 이번 포스트에서는 AWS Lambda를 활용하여 제로 코스트로 Spring Batch를 운용한 경험을 공유한다.   Batch 실행과 문제배치 작업을 실행시키는 방법으로는배치 어플리케이션이 실행되어 있는 상태로 존재하다가 이벤트를 받았을 때 작업을 실행하거나특정 때에 어플리케이션을 실행시켜 작업을 진행한 뒤 어플리케이션이 종료되는 형태일 수도 있다. 필자의 푸시알림 배치작업은 후자와 같다. 문제는 배치 작업이 ..
· Spring
Spring에서는 이벤트 기반 프로그래밍을 지원한다. EventPublisher를 이용해 이벤트를 발행하고 구독하고 있는 객체에서 이벤트를 처리한다. 덕분에 비즈니스 로직과 직접적으로 관련없는 로직들을 이벤트를 통해 처리할 수 있다. 객체간 낮은 결합도를 유지한 상태로 부가적인 로직을 처리할 수 있다는게 매력적이다. '개발 한 스푼' 서비스에서는 질문 답변이나 게시글을 작성할 때마다 활동 테이블에 카운트를 증가시키고 활동점수에 따라 뱃지 등을 취득할 수 있다. 답변이나 게시글 작성 후 활동점수 집계는 문맥이 다르기 때문에 이들은 이벤트를 발행해 처리하고자 했다. 하지만 이벤트를 발행하는 로직 또한 비즈니스 로직 내에 포함된다. 때문에 한 단계 더 나아가 이벤트 발행 로직을 AOP로 분리하여 처리해보았다...
· Spring
동시성 이슈를 예방하고 데이터 일관성을 유지하기 위해서 Lock을 이용한다. 그 중 분산락은 레코드 수준의 잠금보다는 군집 단위에 영향을 미치는 조작, 여러 DB에 걸친 수정 등 복잡한 레벨에서의 일관성을 보장하고자 할 때 활용도가 높다. '개발 한 스푼' 서비스에서도 질문 발급 시 분산락을 적용해야할 상황이 생겼다.(실제 서비스에서 문제가 이미 발생했고 후 처리...) 이번 글에서는 분산락을 도입하게 된 배경과 이를 유연하게 적용하기 위해 구현한 방법을 공유해본다. 이 포스트의 마무리에서는 다음과 같은 방식으로 원하는 부분에 쉽게 분산락을 적용할 수 있다. // 분산락 획득 후 트랜잭션 실행. 분산락 Key는 request에 존재@Transactional@DistributedLock(keyClass =..
· Spring
비즈니스 로직 실행 중 올바르지 않은 결과인 경우 예외를 발생시킨다. 클라이언트로의 응답에는 예외 케이스별로 각기 다른 메시지를 건내주어야한다. 때문에 예외별 필요한 정보들을 따로 정리하여 관리하기도 한다. '개발 한 스푼' 서비스도 Enum을 활용하여 예외별 정보를 모아 관리한다. 하지만 예외 케이스가 많아질수록 예외 정보를 가지는 Enum이 비대해지고 가독성 문제가 생길 수 있기 때문에 프로젝트에 맞게 조금 변형하여 활용해보았다. 이번 글에서는 예외 정보를 확장성 및 가독성 좋게(필자 프로젝트만의 특성일 수도 있지만) 관리하기 위해 적용한 방식을 공유해본다.본 포스트는 다음의 순서로 진행됩니다.1. 단일 Enum으로 예외관리 시 문제점2. 개선하기    2.1 Enum을인터페이스로 확장성 좋게 개선하..
· Spring
Spring Security는 애플리케이션의 인증/인가 관리를 쉽게 처리할 수 있도록 도와준다. 제공하는 기능 중에는 특정 API에 인증없이 요청을 처리할 수 있도록 허용하는 기능(permitAll)도 있다. 필자가 운영하는 '개발 한 스푼' 서비스에서도 Spring Security를 통해 인증을 관리하고 있다. 마찬가지로 인증이 필요없는 API들에는 permitAll을 이용해 인증을 열어주었다. 하지만 API별로 인증을 해제하는 기능은 핸들러 메서드에서 제어하는 것이 아닌 Security 설정 코드에서만 제어할 수 있다. 이는 인증 해제가 필요한 API가 늘어날수록 여러 문제를 초래한다. 이번 글에서는 API별 인증 해제를 효율적으로 처리하기 위해 적용한 방법을 공유해본다.본 포스트는 다음과 같은 순서..
· Spring
이전 포스팅(공통 형식의 응답 효율적으로 처리하기) 에서 공통응답형식을 RequesetBodyAdvice를 구현한 객체에서 처리하였다. 핸들러메서드(Controller 메서드)에서는 실제 결과 데이터 서빙에만 집중할 수 있어 전체적으로 가독성과 개발 생산성이 높아졌다. 하지만 얼마가지 않아 한 가지 문제가 발생하였는데, 바로 핸들러 메서드에서 문자열 응답시 공통응답형식의 적용이 불가능하다는 점이었다. 문자열 응답에도 RequesetBodyAdvice에서 공통형식이 적용되었다면 적어도 아래와 같은 응답을 받아야 하지만 예외가 발생하였다. { code: 200, message: "Success", data: "문자열 응답"} 이번 포스트에서는 필자가 해당 문제를 해결한 과정을 크게 3 부분으로 나눠 공유해본..
· Spring
'개발 한 스푼' 서비스에서는 다음과 같은 형식으로 응답 Body를 보낸다. 성공과 실패 시 같은 응답형식을 취하고 code와 message를 통해 보다 자세한 실패 이유를 알려주기 위함이다. 추후 추가적인 메타정보를 넘겨줄때도 본 데이터에 섞이지 않고 확장시킬 수 있다. // 성공{ "code": 200, "message": "Success", "data" : { } // 성공시 데이터 // 추가적인 데이터가 들어갈 수도(ex. traceId 등)}// 실패시{ "code": 400_001_003, // 내부적으로 유지하는 실패코드 "message": "뭔가 잘못되었습니다."} 핸들러 메서드에서 매번 같은 형식의 응답객체로 래핑하여 응답하는 것은 반복적인 작업임이 분명하..
· Spring
이전 포스트에서 요청/응답 Body에 포함된 Legacy Enum들을 인터페이스를 이용해 다뤘던 방법을 작성하였다. 아쉽게도, '개발 한 스푼' 서비스에서는 쿼리 파라미터에도 Enum 스타일의 소문자 문자열들이 사용되고 있다. Kotlin에서는 Enum값을 대문자로 작성하는 것을 권장하기 때문에 이에 바인딩하는 작업을 커스텀해야한다.이번 글에서는 RequestParam, ModelAttribute에 포함된 다수의 Legacy Enum들을 효율적으로 관리하기 위해 적용한 방식을 공유해본다.본 포스트는 다음과 같은 수순으로 진행됩니다.1. 기존 Converter 톺아보기2. 구현 방향성과 방법   1. 기존 Converter 톺아보기@RequestParam과 @ModelAttribute 를 통해 쿼리 정보들..
· Spring
사용 가능한 값이 제한되어 있는 경우 Enum을 사용하면 가독성과 사용성을 높일 수 있다. 현재 운영중인 '개발 한 스푼' 서비스의 API 요청/응답 Body에서도 이런 Enum 스타일의 필드가 여럿 존재한다. 문제는 해당 필드값들이 소문자 문자열이라는  것이다. 현재 서버리스 API 서버에서 Spring Boot+Kotlin 서버로 마이그레이션 중인데 Kotlin에서는 Enum값을 대문자로 작성하는 것을 권장한다. 이번 글에서는 Body에 포함되어 있는 다수의 Enum 스타일의 소문자 문자열들(Legacy Enum)을 효율적으로 처리하기 위해 적용한 방식을 공유해본다. 해당 포스트는 다음의 수순으로 진행됩니다.1. 기존 가능한 방식과 문제점2. 방향성 및 해결방법   1. 기존 가능한 방식과 문제점1...