You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Migrates chat functionality to Redis Pub/Sub for scalability.
Removes RabbitMQ dependencies.
Implements Redis publisher and subscriber for message handling.
Improves WebSocket handling for chat rooms.
Manages user connections and disconnections.
Stores and retrieves recent messages from Redis.
Adds a default chat room on application start.
Diagram Walkthrough
flowchart LR
A["WebSocket Client"]
B["ChatWebSocketHandler"]
C["RedisPublisher"]
D["RedisSubscriber"]
E["ChatService"]
F["Redis"]
G["Database"]
A -- "Connect/Send Message" --> B
B -- "Publish Message" --> C
C -- "Send to Channel" --> F
F -- "Receive Message" --> D
D -- "Send to Sockets" --> A
B -- "Save Message" --> E
E -- "Save to DB" --> G
Loading
File Walkthrough
Relevant files
Enhancement
7 files
ChatController.java
Updates `getChatMessages` to use `findLatestMessages`
The handleTextMessage method catches all exceptions but doesn't rethrow or handle them in a way that informs the client. Consider sending an error message to the client via the WebSocket to indicate that their message was not processed.
protectedvoidhandleTextMessage(WebSocketSessionsession, TextMessagemessage) throwsException {
try {
ChatMessagechatMessage = chatService.createMessage(message);
chatService.saveMessage(chatMessage);
StringroomId = chatMessage.getRoomId();
StringredisKey = "chat:room:" + roomId;
StringmessageJson = objectMapper.writeValueAsString(chatMessage);
chatRedisTemplate.opsForList().leftPush(redisKey, messageJson);
chatRedisTemplate.opsForList().trim(redisKey, 0, 199);
try {
redisPublisher.publish(chatMessage);
} catch (Exceptione) {
log.error("Failed to publish chat message to Redis, but it is saved in DB. Message: {}", chatMessage, e);
}
} catch (Exceptione) {
log.error("Failed to process chat message. SessionId: {}", session.getId(), e);
}
The chatRooms map is accessed and modified by multiple WebSocket sessions concurrently. Consider using a concurrent-safe data structure like ConcurrentHashMap to avoid potential race conditions.
privateMap<String, ChatRoom> chatRooms;
privatefinalChatRepositorychatRepository;
@Qualifier("chatRedisTemplate")
privatefinalRedisTemplate<String, String> chatRedisTemplate;
// Redis Topic 관련 의존성 추가privatefinalRedisMessageListenerContainerredisContainer;
privatefinalMessageListenerAdaptermessageListener;
privatefinalRedisConfigredisConfig;
// 기본 채팅방을 위한 고정 IDprivatestaticfinalStringDEFAULT_ROOM_ID = "00000000-0000-0000-0000-000000000001";
@PostConstructprivatevoidinit() {
chatRooms = newLinkedHashMap<>();
// 애플리케이션 시작 시, 모든 인스턴스가 동일한 ID를 가진 기본 채팅방을 생성ChatRoomdefaultChatRoom = ChatRoom.builder()
.roomId(DEFAULT_ROOM_ID)
.name("기본 채팅방")
.build();
chatRooms.put(DEFAULT_ROOM_ID, defaultChatRoom);
The onMessage method catches IOException but throws RuntimeException. It's better to handle the exception more gracefully, possibly by logging the error and taking appropriate action, instead of crashing the entire stream processing.
Creating a new ChatRoom if one doesn't exist might lead to unintended consequences, such as creating a large number of empty rooms. Instead, return null if the room doesn't exist, or throw an exception to indicate that the room was not found. Handle the case where the room does not exist in the calling methods.
public ChatRoom findRoomById(String roomId) {
- // 채팅방이 없으면 새로 생성 (기본 채팅방 외 다른 채팅방이 필요할 경우를 대비)- return chatRooms.computeIfAbsent(roomId, id -> ChatRoom.builder().roomId(id).build());+ return chatRooms.get(roomId);
}
Suggestion importance[1-10]: 8
__
Why: The suggestion to avoid auto-creating chatrooms is valuable because it prevents the creation of empty rooms. Returning null if the room doesn't exist is a good approach, and the calling methods should handle this case. This change improves the logic and prevents unintended behavior.
Medium
Replace session ID with username
Instead of using the session ID as the sender's name, which is not user-friendly, retrieve the actual username. If the username is unavailable, consider using a default name like "Guest". This will improve the readability of chat messages.
Why: Replacing the session ID with a username improves the user experience. However, the suggestion assumes that the username is stored in the session attributes, which might not always be the case. It would be better to verify that the username exists and handle the case where it doesn't.
Medium
Use constant for Redis key prefix
Consider extracting the Redis key to a constant or configuration value for better maintainability and to avoid hardcoding the key format. This makes it easier to change the key structure in the future without modifying the code in multiple places.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
User description
#️⃣ 이슈
🔎 작업 내용
https://meteorfish.tistory.com/9
PR Type
Enhancement
Description
Migrates chat functionality to Redis Pub/Sub for scalability.
Improves WebSocket handling for chat rooms.
Adds a default chat room on application start.
Diagram Walkthrough
File Walkthrough
7 files
Updates `getChatMessages` to use `findLatestMessages`Refactors WebSocket handler to use Redis Pub/SubUpdates `getRecentMessages` to use `findLatestMessages`Implements Redis Pub/Sub and manages chat roomsImplements Redis publisher for sending chat messagesImplements Redis subscriber for receiving chat messagesAdds default chat room creation6 files
Removes RabbitMQ related constantsRemoves RabbitMQ consumer service interfaceRemoves RabbitMQ consumer service implementationRemoves RabbitMQ producer service interfaceRemoves RabbitMQ producer service implementationRemoves RabbitMQ configuration3 files
Removes test WebSocket handlerRemoves message queue processing serviceNo changes4 files
Adds conditional property for dummy data loadingExcludes WebSocket config from test profileConfigures Redis connections and message listenersUpdates local DB dialect7 files