Skip to content

Comments

[FIX] 채팅방 lastMessage 및 읽음 처리 동시성 문제 해결 및 성능 개선#286

Merged
1000hyehyang merged 2 commits intodevfrom
fix/285-chat
Feb 6, 2026
Merged

[FIX] 채팅방 lastMessage 및 읽음 처리 동시성 문제 해결 및 성능 개선#286
1000hyehyang merged 2 commits intodevfrom
fix/285-chat

Conversation

@1000hyehyang
Copy link
Member

Summary

채팅방 lastMessage 업데이트와 읽음 처리에서 발생할 수 있는 Race Condition을 조건부 UPDATE로 해결하고, 불필요한 DB 조회를 제거하여 성능을 개선했습니다.

Changes

1. 동시성 문제 해결

  • 채팅방 lastMessage 업데이트 Race Condition 해결

    • ChatRoomRepository.updateLastMessageIfNewer() 추가 (조건부 UPDATE)
    • WHERE last_message_at IS NULL OR last_message_at < :newLastMessageAt 조건으로 더 최신 메시지일 때만 업데이트
    • DB 레벨에서 원자적 연산 보장
  • 읽음 처리 동시성 문제 해결

    • ChatRoomMemberRepository.updateLastReadMessageIfNewer() 추가 (조건부 UPDATE)
    • WHERE last_read_message_id IS NULL OR last_read_message_id < :newId 조건으로 더 큰 메시지 ID일 때만 업데이트
    • 동시 읽음 처리 시에도 항상 최대값 유지

2. 성능 개선

  • 불필요한 조회 제거

    • ChatRoomUpdateServiceImpl.updateLastMessage(): existsById()updatedRows == 0일 때만 실행
    • ChatRoomMemberCommandServiceImpl.updateLastReadMessage(): 성공 시에만 필요한 데이터 조회
  • 이벤트에 userId 포함하여 추가 조회 제거

    • ChatMessagesViewedEventuserId 필드 추가
    • 호출부에서 이미 조회한 member.getUserId()를 이벤트에 포함
    • 성공 케이스에서 findById() 조회 제거 (SELECT 1회 제거)

3. 코드 개선

  • 빈 분기 제거 및 guard clause 적용으로 가독성 향상
  • @Modifying(clearAutomatically = true, flushAutomatically = true) 추가로 영속성 컨텍스트 정합성 보장
  • messageAt null 방어 로직 추가

Type of Change

  • Bug fix (기존 기능에 영향을 주지 않는 버그 수정)
  • New feature (기존 기능에 영향을 주지 않는 새로운 기능 추가)
  • Breaking change (기존 기능에 영향을 주는 수정)
  • Refactoring (기능 변경 없는 코드 개선)
  • Documentation (문서 수정)
  • Chore (빌드, 설정 등 기타 변경)
  • Release (develop → main 배포)

Related Issues

Closes #285

참고 사항

@1000hyehyang 1000hyehyang self-assigned this Feb 6, 2026
@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @1000hyehyang, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

이 PR은 채팅방의 lastMessage 업데이트와 메시지 읽음 처리 과정에서 발생할 수 있는 동시성 문제를 해결하고 전반적인 성능을 개선하는 데 중점을 둡니다. 조건부 업데이트 쿼리를 도입하여 데이터 무결성을 보장하고, 불필요한 데이터베이스 조회를 제거하여 시스템 효율성을 높였습니다. 또한, 코드 가독성과 유지보수성을 향상시키기 위한 리팩토링도 포함되어 있습니다.

Highlights

  • 채팅방 lastMessage 및 읽음 처리 동시성 문제 해결: ChatRoomRepository.updateLastMessageIfNewer() 및 ChatRoomMemberRepository.updateLastReadMessageIfNewer() 메서드를 추가하여 조건부 업데이트를 통해 Race Condition을 방지했습니다.
  • 성능 개선을 위한 불필요한 DB 조회 제거: ChatMessagesViewedEvent에 userId를 포함하고, updateLastReadMessage 및 updateLastMessage 로직에서 불필요한 findById() 호출을 제거했습니다.
  • 코드 가독성 및 안정성 향상: 빈 분기 제거, Guard Clause 적용, messageAt null 방어 로직 추가, @Modifying(clearAutomatically = true, flushAutomatically = true)를 통해 영속성 컨텍스트 정합성을 보장했습니다.
Changelog
  • src/main/java/com/example/RealMatch/business/application/service/CampaignProposalService.java
    • 캠페인 제안 취소 관련 TODO 주석을 제거했습니다.
  • src/main/java/com/example/RealMatch/chat/application/event/ChatMessagesViewedEvent.java
    • 이벤트에 userId 필드를 추가하여 불필요한 조회 없이 사용자 ID를 전달할 수 있도록 했습니다.
  • src/main/java/com/example/RealMatch/chat/application/event/ChatMessagesViewedEventListener.java
    • ChatMessagesViewedEvent 핸들러에서 userId의 null 여부를 확인하고, updateLastReadMessage 호출 시 userId를 전달하도록 변경했습니다.
  • src/main/java/com/example/RealMatch/chat/application/event/apply/ApplySystemMessageHandler.java
    • ChatApplyStatusNoticePayloadResponse 생성 시 event.newStatus()를 포함하도록 변경했습니다.
  • src/main/java/com/example/RealMatch/chat/application/event/proposal/ProposalSystemMessageHandler.java
    • ChatProposalStatusNoticePayloadResponse 생성 시 event.newStatus()를 포함하도록 변경했습니다.
  • src/main/java/com/example/RealMatch/chat/application/service/message/ChatMessageQueryServiceImpl.java
    • ChatMessagesViewedEvent 발행 시 member.getUserId()를 포함하도록 수정했습니다.
  • src/main/java/com/example/RealMatch/chat/application/service/room/ChatRoomMemberCommandService.java
    • updateLastReadMessage 메서드 시그니처에 userId 파라미터를 추가했습니다.
  • src/main/java/com/example/RealMatch/chat/application/service/room/ChatRoomMemberCommandServiceImpl.java
    • updateLastReadMessage 로직을 조건부 업데이트 쿼리(updateLastReadMessageIfNewer)를 사용하는 방식으로 전면 개편하여 동시성 문제를 해결하고 불필요한 findById 조회를 제거했습니다.
    • 업데이트된 행 수에 따라 캐시 무효화를 처리하고, 예상치 못한 업데이트 수에 대한 경고 로그를 추가했습니다.
  • src/main/java/com/example/RealMatch/chat/application/service/room/ChatRoomUpdateServiceImpl.java
    • updateLastMessage 로직을 조건부 업데이트 쿼리(updateLastMessageIfNewer)를 사용하는 방식으로 변경하여 동시성 문제를 해결하고 성능을 개선했습니다.
    • messageAt에 대한 null 방어 로직을 추가하고, 업데이트 실패 시 ROOM_NOT_FOUND 예외를 처리하도록 개선했습니다.
  • src/main/java/com/example/RealMatch/chat/domain/repository/ChatRoomMemberRepository.java
    • updateLastReadMessageIfNewer JPQL 메서드를 추가하여 lastReadMessageId가 현재 값보다 클 경우에만 업데이트하도록 했습니다.
    • @Modifying(clearAutomatically = true, flushAutomatically = true) 어노테이션을 추가하여 영속성 컨텍스트를 관리합니다.
  • src/main/java/com/example/RealMatch/chat/domain/repository/ChatRoomRepository.java
    • updateLastMessageIfNewer JPQL 메서드를 추가하여 lastMessageAt이 현재 값보다 최신일 경우에만 채팅방의 마지막 메시지 정보를 업데이트하도록 했습니다.
    • @Modifying(clearAutomatically = true, flushAutomatically = true) 어노테이션을 추가하여 영속성 컨텍스트를 관리합니다.
  • src/main/java/com/example/RealMatch/chat/presentation/dto/response/ChatApplyStatusNoticePayloadResponse.java
    • applyStatus 필드를 추가했습니다.
  • src/main/java/com/example/RealMatch/chat/presentation/dto/response/ChatProposalStatusNoticePayloadResponse.java
    • proposalStatus 필드를 추가했습니다.
Activity
  • PR이 생성되었습니다.
  • 채팅방의 lastMessage 및 읽음 처리 로직에서 발생할 수 있는 동시성 문제와 성능 저하를 해결하기 위한 변경 사항이 적용되었습니다.
  • 관련 이슈 #285가 해결되었습니다.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

이 PR은 채팅방의 lastMessage 업데이트와 읽음 처리에서 발생할 수 있는 동시성 문제를 조건부 UPDATE 쿼리를 사용하여 효과적으로 해결하고, 불필요한 DB 조회를 제거하여 성능을 개선했습니다. ChatMessagesViewedEventuserId를 포함시켜 추가적인 사용자 조회를 없앤 점과, ChatRoomMemberRepositoryChatRoomRepository에 조건부 업데이트 메서드를 추가하여 데이터 일관성을 보장한 점이 특히 좋습니다. 또한, 업데이트된 행 수를 확인하여 예외 상황을 처리하고 로깅하는 방식은 시스템의 안정성과 디버깅 용이성을 높여줍니다. 전반적으로 코드의 견고성과 효율성을 크게 향상시킨 변경사항입니다.

Long actorUserId,
LocalDateTime processedAt
LocalDateTime processedAt,
ChatProposalStatus applyStatus
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

현재 ChatApplyStatusNoticePayloadResponse에서 applyStatus 필드의 타입으로 ChatProposalStatus를 사용하고 있습니다. 하지만 이 DTO는 'Apply' 상태에 대한 알림을 위한 것이므로, 'Apply'와 관련된 별도의 ApplyStatus enum을 정의하여 사용하는 것이 더 적절하고 의미론적으로 명확합니다. ChatProposalStatus는 'Proposal'에 특화된 상태를 나타내므로, 'Apply' 컨텍스트에서는 혼란을 줄 수 있습니다.

Suggested change
ChatProposalStatus applyStatus
ChatApplyStatus applyStatus

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@gemini-code-assist 비즈니스가 ProposalStatus를 공유해서 그래

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

비즈니스 로직상 ProposalStatus를 공유하는 것이 맞다면, 현재 ChatProposalStatus를 사용하는 것이 타당합니다. 해당 필드가 'Apply'와 'Proposal' 두 가지 컨텍스트에서 모두 사용될 수 있다는 점을 고려하면 현재 구현은 비즈니스 요구사항에 부합합니다.

@1000hyehyang 1000hyehyang merged commit 462d2f8 into dev Feb 6, 2026
1 check passed
@1000hyehyang 1000hyehyang deleted the fix/285-chat branch February 6, 2026 03:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[FIX] PROPOSAL_STATUS_NOTICE와 APPLY_STATUS_NOTICE 모두 payload에 상태 정보 추가

1 participant