[박성조] sprint12#128
Hidden character warning
Conversation
| public void handleMessage(MessageCreatedEvent event) { | ||
| MessageDto message = event.getData(); | ||
| String destination = "/sub/channels.%s.messages".formatted(message.channelId()); | ||
| messagingTemplate.convertAndSend(destination, message); |
There was a problem hiding this comment.
성조님 ~! 아직 심화기능 구현하진 않으셨겠지만,
현재에서 멈추게 되면 어떤 문제인지, 이번 스프린트가 어떤 부분이 중요한 것인지를 위한 리뷰를 살짝만 남길게요~!
위처럼, 그냥 그대로 messagingTemplate.convertAndSend(destination, message); 만 해버리면 문제가 생깁니다.
대부분의 실시간 이벤트가 로컬 전송이라 인스턴스가 여러개일 떄 다른 인스턴스의 클리어은트는 이벤트를 못 받는 구조가 되어버려요.
TransactionalEventListener 는 같은 jvm 내에서만 동작하는 거잖아요.
인스턴스 3개 띄우면
유저 A -> app1 에서만 채널 생성되고 app1 의 sse/소켓 클라이언트만 이벤트 받고, app2, app3 클라이언트는 아무것도 못 받게 되거든요~!
중간에 다른 매개체가 필요한 것 같아요. kafka 같은 것 통해서 모든 인스턴스에 브로드캐스트하는 방식으로 추가 구현이 필요할 것 같습니다~!
| jwtRegistry.invalidateJwtInformationByUserId(userId); | ||
| }); | ||
| } | ||
| Arrays.stream(request.getCookies()) |
There was a problem hiding this comment.
null check 제거로 npe 위험이 생기게 되었습니다!
| kafkaTemplate.send("discodeit.".concat(event.getClass().getSimpleName()), payload); | ||
| } catch (JsonProcessingException e) { | ||
| log.error("Failed to send event to Kafka", e); | ||
| throw new RuntimeException(e); |
There was a problem hiding this comment.
이전에는 로그만 남겼는데, 이제 예외를 던지게 되었는데요.
이 리스너는 @TransactionalEventListener에서 호출될 수 있는데, 트랜잭션 커밋 후 예외가 발생하게 되면,
이미 DB에는 커밋이 되었는데, 호출자에게 예외가 전파가 되어요. 즉 씽크가 안 맞는거죠. 양쪽이 다른겁니다.
유저 입장에서는 "메시지 생성 실패"처럼 보이지만, 실제로는 DB에 저장돼 있어요.
그래서 여기에서 사실, JsonProcessingException은 코드 버그이므로, 로그 + 모니터링 알림이 더 적합할 것 같아요!
|
|
||
| backend: | ||
| image: discodeit-backend:local | ||
| container_name: discodeit-backend |
There was a problem hiding this comment.
이 부분은 나중에 분산 구조로 변환할 떄 수정을 해야할 것 같아요!
containier_name 이 들어가게 되면 replicas 가 불가능하거든요~!
| data.compute(receiverId, (key, emitters) -> { | ||
| List<SseEmitter> next = emitters == null ? new ArrayList<>() : new ArrayList<>(emitters); | ||
| next.add(emitter); | ||
| return next; |
There was a problem hiding this comment.
매번 새로운 list 를 생성하는데요.
아래 remove 에서도요.
compute 내에서 복사본을 만드는 건 thread-safety를 위한 의도적인 선택인 것 맞죠!? (읽기 시 락 없이 안전하니까요). 하지만 접속자가 많을 때 add/remove가 빈번하면 GC 압박이 생길 수 있어요. 힙 메모리 관련 공부해보세요~! 그래서 여기에서는 CopyOnWriteArrayList를 쓰면 동일한 로직인데 내부 구현이 그것을 그대로 구현하고 있어요. 공부해보세요~!
보통 읽기가 빈번하고, 쓰기그 드물 때 사용하면 좋습니다. 바로 이번처럼요~!
읽기 빈번 - 이벤트 발행할 떄마다 emitter 순회하면서 전송
쓰기 드묾 - 유저가 연결/해제할 때만(분당 수회)
- SSE 메시지 모델 추가: `SseMessage` 클래스 도입 및 브로드캐스트/수신자 필터링 기능 구현 - WebSocket 및 SSE 채널 인증: `JwtAuthenticationChannelInterceptor` 도입 - Kafka 이벤트 리스너 구현: `SseRequiredTopicListener`에서 주요 이벤트 처리 및 SSE 전송 - Redis 캐싱 통합: `RedisConfig` 및 `RedisLockProvider` 추가 - 이벤트 기반 설계 확장: BinaryContent, Channel, User 관련 이벤트 처리 개선 및 SSE 연동 - 기본 RedisLockProvider로 분산 락 구현 - 불필요한 코드를 정리하고 이벤트 생성 및 처리 로직을 효율화
- `application-dev.yaml`에서 환경변수 참조 제거 및 정적 값으로 대체 - SSE 타임아웃 설정 추가 (`application.yaml`)
- `SseEmitterRepository`, `SseMessageRepository`, `SseService` 삭제 - 사용되지 않는 SSE 관련 코드 정리 및 의존성 제거 - `application-dev.yaml`에서 민감 정보 값 표시 방식 수정
요구사항
기본
심화
멘토에게