SSE 구조 문제
✔ 문제 1
💢 알림을 보내야 할 주체를 특정하기가 어렵다.
➡ 어떤 유저에게 알림을 보내줄 것인가?
➡ 포스트를 보고 있는 사람을 어떻게 특정할 것인가?
✅ 유저와 포스트를 특정할 수 있도록 ID를 부여하도록 했다. Ssemitter와 묶기 위해 객체를 하나 만들었다.
✔ ID와 Ssemitter가 묶인 클래스
public record CustomSseEmitter (
Long id,
SseEmitter sseEmitter
) {}
✔ 문제 2
💢 알림과 실시간 입찰 가격 조회를 하나의 SSE를 사용할 경우 문제가 발생한다는 것을 알았다.
➡ 필요하지 않은 이벤트 전송이 일어난다. [ 경매를 참여하지 않은 클라이언트에게도 이벤트가 날아가는 경우가 생김 ]
💬 유저와 데이터가 많아질수록 SSE 하나 만드는 비용보다 필요하지 않은 이벤트를 전송하는 비용이 더 많이 든다고 판단
✅ 알림과 실시간 입찰 가격을 분리하여 2개의 SSE를 생성하고 관리하기로 했다.
➡ 분리하여 관리하기 위해 connect, event type이 필요하고 생각
➡ 2개의 SSE를 관리하기 위한 컨테이너와 connect, event type을 적용하기 위해 service 코드 수정
✔ Connect type 정의
public enum SseConnect {
NOTIFICATION, BID
}
✔ Event type 정의
public enum SseEvent {
BID_PRICE_UPDATE, NOTICE_BID_END, NOTICE_BID_PRICE_UPDATE, NOTICE_BID_START_BEFORE
}
✔ Service 수정
public class SseService {
private static final Long DEFAULT_TIMEOUT = 1000 * 60 * 30L;
private static final List<CustomSseEmitter> noticeEmitters = new ArrayList<>();
private static final List<CustomSseEmitter> bidEmitters = new ArrayList<>();
public SseEmitter connect(SseConnect type, Long id, String lastEventId) {
SseEmitter emitter = new SseEmitter(DEFAULT_TIMEOUT);
List<CustomSseEmitter> currentEmitters = type == SseConnect.NOTIFICATION
? noticeEmitters
: bidEmitters;
String initMessage = type == SseConnect.NOTIFICATION
? "connect user : " + id
: "connect idea : " + id;
CustomSseEmitter customSseEmitter = new CustomSseEmitter(id, emitter);
currentEmitters.add(customSseEmitter);
emitter.onCompletion(() -> currentEmitters.remove(customSseEmitter));
emitter.onTimeout(() -> currentEmitters.remove(customSseEmitter));
try {
emitter.send(initMessage);
} catch (IOException e) {
throw new RuntimeException(e);
}
return emitter;
}
public void send(SseConnect type, SseEvent event, Long id, Object data) {
List<CustomSseEmitter> currentEmitters = type == SseConnect.NOTIFICATION
? noticeEmitters
: bidEmitters;
List<CustomSseEmitter> sendEmitters = currentEmitters.stream()
.filter((customSseEmitter) -> customSseEmitter.id() == id).toList();
for(CustomSseEmitter sendEmitter : sendEmitters) {
try {
sendEmitter.sseEmitter()
.send(SseEmitter.event()
.name(event.toString())
.data(data));
} catch (IOException exception) {
currentEmitters.remove(sendEmitter);
throw new RuntimeException("연결 오류!");
}
}
}
}
'개발일지 > TIL' 카테고리의 다른 글
[230812] 성능 테스트 툴 선정 (0) | 2023.08.12 |
---|---|
[230811] Java Faker로 더미 데이터 생성 (0) | 2023.08.11 |
[230809] 알림 기능 구현 (0) | 2023.08.09 |
[230808] Polling, SSE, WebSocket ? (0) | 2023.08.08 |
[230807] Java Security AutoConfigure가 될 때 Https Port 매핑 (1) | 2023.08.07 |