글의 결론
1. 영속성 컨텍스트는 스레드별로 관리된다. 따라서 비동기 처리한다면 영속성 컨텍스트가 상이하거나 초기화 되지 않는 것을 고려해야 한다.
2. 이벤트 리스너는 이벤트를 발행한다고 바로 실행되는 것이 아니다.
전자 결재, 그룹웨어 사이드 프로젝트를 진행중입니다.
오늘은 결재 문서에서 아래 상신 버튼을 눌렀을 때 발생하는 서버 통신에서
성능 최적화를 위해 비동기 처리를 하면서 겪었던 내용을 담았습니다.
클라이언트(사용자)가 상신 버튼을 누르면 아래와 같은 흐름으로 통신합니다.
참고로 전자 결재, GW 포탈은 서로 다른 서버입니다.
이를 가장 간단하게 구현하는 방법은 전자 결재 서버에서 동기적으로 처리하는 것이다. 즉 아래 과정을 하나의 스레드, 트랜잭션으로 묶는 것이다.
1. 상신 API 호출
2. 트랜잭션 시작
3. 상신 처리를 위한 작업 (WRITE QUERY)
4. GW 후속 처리 API 호출
5. 트랜잭션 커밋
6. 응답
동기적으로 처리할 경우 문제가 되는 부분은 4이다. 4 과정에서 네트워크 I/O, DB I/O 가 발생하게 된다. 추가로 4번 서버 환경에 따라 응답이 늦어질 수도 있다.
위 과정을 아래와 같이 변경한다. 트랜잭션이 GW 후속 처리 API 호출 이전에 종료되는 것이 차이점입니다.
1. 상신 API 호출
2. 트랜잭션 시작
3. 상신 처리를 위한 작업 (WRITE QUERY)
4. 트랜잭션 커밋
5. GW 후속 처리 API 호출 (비동기)
6. 응답
위와 같이 phase 속성을 주면 ConfirmDocumentRaiseEvent 를 발행한 메서드의 트랜잭션이 커밋된 이후에 실행되기 때문에
트랜잭션 종료 후, GW 후속 처리 API를 호출 할 수 있다.
이제 로그를 보며 트랜잭션과 스레드가 분리된 것을 확인해보자.
(1) 블록은 1번부터 4번까지의 처리를 나타내며 exec-9 스레드 ConfirmDocuementService 트랙잭션이 처리하고 있다.
(2) 블록은 5번 처리를 나타내며 task-1 스레드 DefaultConfirmDocumentRestApiAdapterService 트랜잭션이 처리하고 있다.
사실 5번 과정에서는 네트워크 I/O만 발생하기에 새로운 트랜잭션을 만들 필요는 없다. 설명을 위해 추가한 코드
결과적으로 위와 같이 5번을 비동기로 처리하면 아래 같은 이점을 가질 수 있음
1. 더 짧은 트랜잭션 유지 시간
2. 더 빠른 전자 결재 상신 API 응답 속도
다만 문제는 5번 과정에서 생기는 문제는 전자 결재 서버에서 알기 어려움, 이를 보완하기 위해 또 추가 로직이 필요함
(3) 경우에는 영속성 컨텍스트 관련된 로그이다.
영속성 컨텍스트는 하나의 스레드에서 만들어진다. 즉, 전역적으로 생성되는것이 아니다. (2차 캐시는 논외)
여기서 첫번째 파라미터 confirmDocument 는 exec-9 스레드에서 생성되어 넘어오게 된다.
그래서 task-1 스레드에서는 해당 confirmDocument 객체가 관리되고 있지 않아 false 가 반환되는 것을 볼 수 있다.
위와 같이 @Async 애노테이션을 주석 처리 후, 테스트 해보면 아래와 같이 동일한 스레드에서 아래 로직이 처리되기에 영속성 컨텍스트에서도 confirmDocument 객체가 관리되고 있다는 것을 볼 수 있다.
'개발일기장' 카테고리의 다른 글
사이드 프로젝트 일기 2 - 업무 시스템과 전자 결재 연동하기 (0) | 2025.03.04 |
---|---|
스프링 부트 환경에서 도커를 찍먹해보자 feat. war 파일 (0) | 2025.03.02 |
vscode 단축키 설정 (0) | 2024.03.03 |
백엔드 서적, 인강 리뷰 1 (1) | 2023.11.19 |
Postman 조금 더 잘 사용하기 - 반복적이고 랜덤하게 API 호출하기 (1) | 2023.11.18 |