Skip to content

[FIX] 채팅 신뢰성 개선 - 멱등성 2단계 상태, DLQ 크기 제한, lastMessage 정밀도, 논리 실패 메트릭 (#317)#320

Merged
1000hyehyang merged 3 commits intodevfrom
fix/317-chat
Feb 8, 2026
Merged

[FIX] 채팅 신뢰성 개선 - 멱등성 2단계 상태, DLQ 크기 제한, lastMessage 정밀도, 논리 실패 메트릭 (#317)#320
1000hyehyang merged 3 commits intodevfrom
fix/317-chat

Conversation

@1000hyehyang
Copy link
Copy Markdown
Member

Summary

채팅 시스템에서 발견된 신뢰성·관측성 이슈 4가지를 수정했습니다.

  1. 멱등성 선점 후 조용한 유실: SETNX 선점 후 프로세스 다운 시 키가 6시간 동안 남아, 실제 미처리 메시지가 유실되던 문제를 2단계 상태머신(IN_PROGRESS 3분 → PROCESSED 6시간)으로 해결
  2. DLQ 무한 증가: Redis List chat:dlq에 RPUSH 후 LTRIM을 적용해 최대 10,000건만 유지
  3. lastMessage 최신성 오판: 동일 lastMessageAt 시 비교 불가 문제를 (lastMessageAt, lastMessageId) 튜플 비교로 해결
  4. 논리 실패 관측성 부족: Micrometer Counter chat.system_message.logical_failure로 eventType, reason 태그 기반 관측 가능

Changes

  • ProcessedEventStore / RedisProcessedEventStore

    • markIfNotProcessed(eventId, inProgressTtl): IN_PROGRESS 상태로 선점, 짧은 TTL(3분)
    • markAsProcessed(eventId, processedTtl): PROCESSED 상태로 승격, 긴 TTL(6시간)
    • 선점 후 프로세스 다운 시 IN_PROGRESS TTL 만료 후 재처리 가능
  • FailedEventDlq

    • RPUSHLTRIM으로 최근 10,000건만 유지
    • MAX_DLQ_SIZE = 10_000 상수 추가
  • ChatRoomRepository

    • updateLastMessageIfNewer WHERE 조건에 (r.lastMessageAt = :messageAt AND r.lastMessageId < :messageId) 타이브레이크 추가
  • SystemMessageRetrySender

    • IN_PROGRESS_TTL(3분), PROCESSED_TTL(6시간) 상수 분리
    • 논리 실패 시 chat.system_message.logical_failure Counter 기록 (eventType, reason 태그)
    • MeterRegistry 의존성 추가

Type of Change

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

Related Issues

Closes #317

참고 사항

@1000hyehyang 1000hyehyang self-assigned this Feb 8, 2026
@gemini-code-assist
Copy link
Copy Markdown
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!

이 Pull Request는 채팅 시스템의 신뢰성과 관측성을 향상시키기 위한 네 가지 주요 개선 사항을 포함합니다. 이벤트 멱등성 처리 로직을 2단계 상태 머신으로 고도화하여 잠재적인 메시지 유실을 방지하고, DLQ의 메모리 사용량을 효율적으로 관리합니다. 또한, 채팅방의 마지막 메시지 업데이트 로직을 개선하여 최신성 판단의 정확도를 높였으며, 시스템 메시지 전송 과정에서 발생하는 논리적 실패에 대한 가시성을 확보하여 문제 진단 및 대응 능력을 강화했습니다.

Highlights

  • 멱등성 처리 개선: 기존 SETNX 선점 방식에서 발생할 수 있는 '조용한 유실' 문제를 해결하기 위해 2단계 상태 머신(IN_PROGRESS 3분 → PROCESSED 6시간)을 도입했습니다. 프로세스 다운 시 IN_PROGRESS 상태가 빠르게 만료되어 재처리가 가능해집니다.
  • DLQ(Dead Letter Queue) 크기 제한: Redis List에 저장되는 DLQ(chat:dlq)가 무한정 증가하는 것을 방지하기 위해, RPUSHLTRIM을 적용하여 최대 10,000건만 유지하도록 변경했습니다.
  • lastMessage 최신성 판단 정밀도 향상: 동일한 lastMessageAt 값을 가진 메시지들 사이에서 최신성을 정확히 판단하기 위해, (lastMessageAt, lastMessageId) 튜플을 비교하는 방식으로 ChatRoomRepositoryupdateLastMessageIfNewer 쿼리를 수정했습니다.
  • 논리 실패 관측성 강화: 시스템 메시지 전송 중 발생하는 논리적 실패를 더 잘 관측할 수 있도록 Micrometer Counter chat.system_message.logical_failure를 추가했습니다. 이 카운터는 eventTypereason 태그를 포함하여 실패 원인을 세분화하여 모니터링할 수 있습니다.
Changelog
  • src/main/java/com/example/RealMatch/chat/application/event/sender/SystemMessageRetrySender.java
    • Micrometer CounterMeterRegistry 임포트 추가
    • METRIC_LOGICAL_FAILURE 상수를 정의하여 논리 실패 메트릭 이름 지정
    • IN_PROGRESS_TTL (3분) 및 PROCESSED_TTL (6시간) 상수를 분리하여 2단계 멱등성 TTL 관리
    • sendWithIdempotency 메서드에서 markIfNotProcessed 호출 시 IN_PROGRESS_TTL 사용
    • 논리적 실패 발생 시 recordLogicalFailure 메서드를 호출하여 메트릭 기록 추가
    • markAsProcessed 호출 시 PROCESSED_TTL 사용으로 변경
    • 논리 실패 메트릭을 기록하는 recordLogicalFailure 프라이빗 메서드 추가
    • 논리 실패 예외의 원인을 분석하는 resolveLogicalFailureReason 프라이빗 메서드 추가
  • src/main/java/com/example/RealMatch/chat/application/idempotency/FailedEventDlq.java
    • MAX_DLQ_SIZE 상수를 10,000으로 정의하여 DLQ 최대 크기 설정
    • enqueueFailedEvent 메서드에서 redisTemplate.opsForList().trim(DLQ_KEY, -MAX_DLQ_SIZE, -1)을 추가하여 DLQ 크기 제한 로직 구현
  • src/main/java/com/example/RealMatch/chat/application/idempotency/ProcessedEventStore.java
    • 인터페이스 Javadoc을 2단계 멱등성 상태 머신(IN_PROGRESS, PROCESSED)에 대한 설명으로 업데이트
    • markIfNotProcessed 메서드의 파라미터 ttlinProgressTtl로 변경하고 Javadoc 업데이트
    • markAsProcessed 메서드의 파라미터 ttlprocessedTtl로 변경하고 Javadoc 업데이트
  • src/main/java/com/example/RealMatch/chat/application/idempotency/RedisProcessedEventStore.java
    • 클래스 Javadoc에 2단계 멱등성 상태 머신(IN_PROGRESS, PROCESSED)에 대한 설명 추가
    • VALUE_IN_PROGRESSVALUE_PROCESSED 상수를 정의하여 상태 값 명확화
    • markIfNotProcessed 메서드에서 VALUE_IN_PROGRESSinProgressTtl을 사용하여 Redis SETNX 호출
    • markAsProcessed 메서드에서 VALUE_PROCESSEDprocessedTtl을 사용하여 Redis SET 호출
    • 로그 메시지 및 예외 메시지를 2단계 상태 머신에 맞게 업데이트
  • src/main/java/com/example/RealMatch/chat/domain/repository/ChatRoomRepository.java
    • updateLastMessageIfNewer 쿼리의 WHERE 조건에 (r.lastMessageAt = :messageAt AND r.lastMessageId < :messageId) 타이브레이크 로직을 추가하여 lastMessageAt이 동일할 경우 lastMessageId로 최신성 판단
Activity
  • 현재까지 이 Pull Request에 대한 인간 활동(댓글, 리뷰 등)은 없습니다.
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
Copy Markdown
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은 중요한 이슈들을 해결하고 있어 시스템 안정성에 크게 기여할 것으로 보입니다.

주요 변경 사항에 대한 제 생각은 다음과 같습니다:

  • 2단계 멱등성 처리: IN_PROGRESSPROCESSED 상태를 분리하여 프로세스 다운 시 메시지 유실을 방지하는 아이디어는 매우 훌륭합니다. TTL을 다르게 설정하여 안정성과 재처리 가능성을 모두 확보한 점이 인상적입니다.
  • DLQ 크기 제한: LTRIM을 사용하여 Redis 메모리가 무한정 증가하는 것을 막은 것은 운영 안정성을 위한 필수적인 조치입니다.
  • lastMessage 정밀도 향상: lastMessageId를 타이브레이커로 사용하여 동일 타임스탬프 문제를 해결한 것은 엣지 케이스를 잘 처리한 좋은 예입니다.
  • 논리 실패 메트릭 추가: Micrometer를 사용하여 논리적 실패를 추적할 수 있게 되어 시스템 관측성이 크게 향상될 것입니다.

전반적으로 매우 신중하고 완성도 높은 수정이라고 생각합니다. 코드 개선을 위해 몇 가지 작은 제안을 리뷰 코멘트로 남겼으니 확인 부탁드립니다. 수고하셨습니다!

@1000hyehyang 1000hyehyang merged commit 66941a3 into dev Feb 8, 2026
1 check passed
@1000hyehyang 1000hyehyang deleted the fix/317-chat branch February 8, 2026 08:41
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.

[REFACTOR] 채팅 기능 리팩토링

1 participant