
(이 글은 외로운 우테코 5기 취준생 “김동욱”, “이건회” aka “그레이”, “하마드”가 작성했습니다.) 현재 비동기 호출과 FCM의 sendAsync를 통해 FCM 알림 호출까지 비동기로 처리하고 있다. 하지만… String response = FirebaseMessaging.getInstance().sendAsync(message).get(); 여기서 get() 메서드가 자꾸 눈에 걸렸다. 자바 5에서 비동기 함수의 리턴 값을 받을 수 있도록 Future 객체가 등장했고 Future 객체에 값을 꺼내기 위해 get 메서드를 사용한다. FirebaseMessaging의 sendAsync의 반환 타입인 ApiFuture에서 get 꺼내는 동작을 찾아보니 블록킹 방식으로 동작하고 있었다. 추가적으로 자..

문제 발생 비동기 처리와 스레드 풀 튜닝을 통해 알림 기능을 개선하며 성능 테스트 하던 중, 문제가 발생했다. ?????????????? 갑자기 CPU 수치가 급등해 99.9%를 찍게 되는 현상을 발견했다. 알림을 처리하는 중 간헐적으로 발생하는 것이 아닌, 배포를 완료한 직후 요청(초반)에만 발생한 후 천천히 내려가는 것을 파악했다. 가용 중인 애플리케이션에서 CPU 수치가 99%를 찍는다는 것은 굉장히 위험한 징후다. 누가 CPU를 좀먹고 있었을까? 해당 현상을 확인하기 위해 다양한 시도를 했다. * 배포 직후 스레드 덤프 → 총 32개 스레드 먼저 스레드 덤프를 통해 확인해보니 알림 요청이 오기 전에는 비동기 스레드가 생성되지 않다가, 알림 요청이 온 이후에야 스레드가 생성 후 RUNNABLE 상태..

(이 글은 외로운 우테코 5기 취준생 “김동욱”, “이건회” aka “그레이”, “하마드”가 작성했습니다.) 동기적 알림 처리를 비동기로 수정 @Component @RequiredArgsConstructor public class NotificationEventListener { private final NotificationService notificationService; @EventListener @Async public void handleNotificationEvents(NotificationEvents notificationEvents) { for (NotificationEvent event : notificationEvents.getNotificationEvents()) { notificat..

(이 글은 외로운 우테코 5기 취준생 “김동욱”, “이건회” aka “그레이”, “하마드”가 작성했습니다.) 사건의 발단 때는 23년 12월 말...하반기 공채에 무참히 실패한 우테코 5기 수료생 두 남자가 만났다. 서울대입구 라멘집에서 늘 그렇듯 일상적인 개발 얘기를 하던 와중 말을 꺼냈다. "피움(23년에 진행한 식물 관리 서비스 프로젝트)의 알림 기능이 문제가 많아 보인다. 프로젝트 막판이라 생각없이 짠 코드가 너무 많다." 처음에 그 말을 꺼냈을 때는 별 관심이 없어 보였다. "이미 끝난 프로젝트이기도 하고...알림? 그거 내가 짠 기능 아닌데? 굳이 신경써야 하나? 그냥 다른 프로젝트 하면 안돼?ㅎㅎ" 하마드는 대충 이런 생각이었다. 하지만 식사 후 서울대입구역 집무실에서 내가 그에게 이 프로젝..

피움 서비스의 런칭 페스티벌을 무사히 마쳤습니다. 런칭 일정에 맞춰 빠르게 개발을 진행하다 보니 꼼꼼하지 못한 부분이 존재했고, 다음 개발에 착수하기 전 부족한 부분을 개선하고 넘어가기로 했습니다. 먼저 서비스 내에서 발생하는 모든 쿼리를 정리해보았습니다. 현재 서비스의 모든 기능을 인수 테스트로 작성했기 때문에 인수 테스트를 하나씩 돌려보며 발생하는 쿼리를 추적했습니다. JPA를 사용하는 환경에서 스프링 properties 설정 중 아래 옵션을 설정하면 쿼리를 확인할 수 있습니다. spring.jpa.show-sql=true spring.jpa.properties.hibernate.format_sql=true 현재 서비스에서 사용하고 있는 API에서 발생하는 쿼리를 위와 같이 정리하였고 개선이 필요한 ..

nullable = false ?? JPA를 이용해 엔티티를 설계하다가 @NotNull 어노테이션과 @Column의 nullable=false의 차이점이 궁금해져 알아보았습니다. JPA는 엔티티를 매핑하고 설계하면 자동으로 DDL을 생성해 주는 기능을 제공합니다. 또한 엔티티의 각 컬럼들에 대해 NOT NULL, UNIQUE 등과 같은 제약 조건이 포함되는 경우에도 자동으로 DDL을 생성해 줍니다. 엔티티를 설계할 때 일반적으로 @Column 어노테이션을 활용합니다. @Column 어노테이션에서 해당 컬럼의 NOT NULL 제약을 설정할 수 있는데 @Column(name = "email", nullable = false)와 같이 nullable=false 설정을 걸어주면, 해당 제약 조건을 명시할 수 있..

Before(Service -> Repository) 지하철 미션을 진행하면서 리뷰어분께 다음과 같은 피드백을 받았다. 현재 지하철 애플리케이션에는 지하철 노선과 관련된 비즈니스 로직을 담당하는 LineService가 있고, 노선의 역과 관련된 비즈니스 로직을 담당하는 StationService가 있다. 각 서비스 계층에 연결된 LineRepository, StationRepository도 함께 존재했다. 계층형 구조를 가져가면서 Service가 다른 도메인의 Repository(DAO)를 참조하는 것은 당연하다고 생각했다. 오히려 Service가 다른 Service를 의존하는 형태를 지양했다. 왜냐하면 계층형 구조에서 Service가 Service를 참조하는 구조는 순환참조가 발생할 수 있다고 생각했고..

스프링 프레임워크에서 필터와 인터셉터는 웹 애플리케이션의 요청 및 응답을 처리하기 전후에 실행되는 컴포넌트이다. 스프링에서 컨트롤러로 요청이 들어오기 전에 처리해야 하는 작업이 있다. 애플리케이션 여러 로직에서 공통으로 관심이 있는 있는 것을 공통 관심사(cross-cutting concern)라고 하는데 대표적으로 인증, 인가, 로깅 등이 있고 주로 필터와 인터셉터를 통해 해당 기능을 수행한다. 필터와 인터셉터 두 컴포넌트 모두 비슷한 목적을 가지고 있지만, 사용되는 시점과 적용되는 방식에 차이가 있다. 필터(Filter) public interface Filter { public default void init(FilterConfig filterConfig) throws ServletException..

문제상황 컨트롤러 테스트를 작성하던 중 Mock 객체를 사용해 서비스 로직 반환 값을 지정했는데도 불구하고 null 값이 반환되는 상황이 발생했다. @Test @DisplayName("가게를 정상적으로 생성한다.") void createSuccess() throws Exception { StoreRequest storeRequest = createRequest(); StoreResponse storeResponse = createResponse(); when(storeService.save(storeRequest)).thenReturn(storeResponse); ResultActions resultActions = mockMvc.perform(post("/api/v1/stores") .with(csrf..
- Total
- Today
- Yesterday
- 백준
- ZNS SSD
- ZNS
- dm-zoned 코드분석
- 네트워크
- 8주차 회고
- 스프링 부트
- 우테코 회고
- java
- 스프링 프레임워크
- 2차 데모데이
- jpa
- 프로젝트
- 스프링MVC
- 3차 데모데이
- dm-zoned
- 런칭 페스티벌
- CI/CD
- 스프링 Logback
- 피움
- 회고
- 팀프로젝트
- 환경 별 로깅 전략 분리
- 우테코
- 알림기능개선기
- 파이썬
- 5주차 회고
- 알림개선기
- Spring
- 피움 6주차 회고
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 |