티스토리 뷰
프로젝트 오픈 후 모니터링 중 타사의 API 호출이 안되는 경우가 발생했다. 에러 로그도 없이 호출이 안되는 상황....뭘까..?
상황은 이랬다.
우리 시스템으로 요청이 오면 서비스단에서 DB를 확인 한 후, 해당 데이터의 종료시간이 null인 경우에만 타시스템에 요청을 보내게 되어있다.
문제는 타시스템에 요청을 하고 응답을 받는 시간이 꽤 길어서 마냥 기다리기만 할 수 없다는 것이다.
따라서, 쓰레드를 생성하여 요청을 하고(응답값은 프로그램에 영향을 미치지 않고,DB에만 저장된다), 원래의 단일 쓰레드에서 종료시간을 업데이트 했다.
이게, 단순히 테스트를 할 때는 문제가 되지 않았는데..오픈 후 많은 많은 요청이 발생하니 조회와 업데이트의 순서가 보장되지 않아, 실제로 요청을 보내야 할 건들의 종료시간이 먼저 업데이트가 되어버려 타API로 요청을 보내지 못하였다.
이를 어떻게 해결 할 수 있을까?
가장 처음 생각한 것은 당연 Thread.sleep이었다.. 하하 그렇지만 실제 운영하는 서비스에서 그럴 수는 없지..
Thread.sleep을 사용하는 경우에는 잠자는 시간동안 워커스레드를 점유한 상태에서 아무것도 못하게 되는 상황이 되어버린다.
그럼 그냥 타사 API 요청이 끝나면 종료시간 업데이트를 치면 되는거 아니야? 할 수도 있겠지만.. 나는 이게 싫었다.
종료시간이 정확할 필요는 없었지만, 큰 차이가 있어서는 안된다고 생각했고...그렇게 한다면 모듈들의 역할 분리가 안된다고 생각했다.
(그렇지만 난 이때 명확한 해결책도 모르고... 해당 소스를 작성하신 분은 그냥 이 방법을 선택하셨다)
그러다 오랜만에 공부하려고 꺼내든.. modern java in action 에서 Executors.newScheduledThreadPool을 보았다..
(프로젝트 초반에 산 책인데 아직 다 못읽었다...반성🥲)
항상 Executors.newFixedThreadPool()을 사용 했었는데, 이 방법을 그 때 알았다면 이걸 제안했을 것이다.
newScheduledThreadPool는 스레드 풀을 생성하여 일정 시간이 지난 후 실행하거나 주기적으로 실행할 수 있도록 명령을 예약할 수 있다.
ScheduleExecutorService 인터페이스를 보면, schedule, scheduleAtFixedRate, scheduleWithFixedDelay 이 메소드들이 존재하며, 내가 사용할 것은 schedule 메소드이다.
아래는 단순화 한 예제코드이다.
타API요청 코드를 지체 없이 바로 실행시킨 후, DB의 종료시간을 업데이트 하는 코드를 5초후에 실행 될 수 있도록 했다.
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class StreamMain {
public static void main(String[] args) {
ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(2);
scheduler.schedule(StreamMain::work1, 0, TimeUnit.SECONDS);
scheduler.schedule(StreamMain::work2, 5, TimeUnit.SECONDS);
System.out.println("응답값 리턴");
}
public static void work1() {
//타 API 요청 코드
//DB의 종료시간 null인지 확인
System.out.println("work1 시작");
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("work1 종료");
}
public static void work2() {
//DB 종료시간 업데이트
System.out.println("DB에 종료 시간 업데이트");
}
}
이와 같이 ScheduledExecutorService 를 사용하는 경우의 장점은 아래와 같다.
- 작업을 비동기로 실행 → work1이 실행되는 동안 메인 스레드는 응답을 리턴 가능
- 멀티스레드 사용 가능 → ScheduledExecutorService는 내부적으로 스레드 풀을 관리하여 동시에 여러 작업을 실행할 수 있음
- 불필요한 대기 시간 제거 → Thread.sleep(10000)처럼 메인 스레드를 블로킹하지 않음
- 유연한 예약 가능 → 특정 시간 이후 실행(schedule), 반복 실행(scheduleAtFixedRate 등) 가능
'백엔드 > java' 카테고리의 다른 글
[java/자바] WebClient 사용하기 - 비동기(subscribe) vs 동기(block) 사용의 차이점 (1) | 2025.02.02 |
---|---|
[java] 소켓 통신 시 데이터가 제대로 오지 않는다?! / 엔디안 / 빅엔디안 / 리틀엔디안 / ByteBuffer (1) | 2024.09.18 |
[java] null 대신 Optional 클래스 (0) | 2024.09.18 |
[java] 신뢰할 수 없는 인증서(사설인증서)를 사용 할 수 있도록 jvm 설정하기/PKIX path building failed (0) | 2024.06.10 |
[자바] 객체를 더 객체답게 사용하기 - 상속(Inheritance) (1) | 2023.12.26 |
- Total
- Today
- Yesterday
- 도커
- 현대
- 자바코테
- softeer java
- 전자정부프레임워크
- Kubernetes
- softeer
- mysql
- java 코테
- react
- 리액트
- Docker
- java
- tomcat
- 아파치카프카
- 자바
- 쿠버네티스
- 코딩테스트
- 현대오토에버
- 코테
- 스프링
- 톰캣
- Linux
- javascript
- 현대코테
- springboot
- 오토에버코테
- Spring
- centos
- 자바스크립트
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |