Skip to content

[FB-260] Internal MQ publisher confirm이 SaveChanges·NotifySaved를 막아 문파·그룹·저장이 멈춤 #681

Closed

Description

@boyism80

심각도

medium

근거 강도

확실

대상 커밋

1a672d602 (FB-252 형제 스윕, 224회차)

위치

  • server/http/Service/RabbitMqService.cs:9-13 (PublishChannelOptions: publisherConfirmationTrackingEnabled, rate limiter null)
  • RabbitMqService.cs:17 (_channelLock 프로세스 단일)
  • RabbitMqService.cs:120-144 (락 안 BasicPublishAsync, 토큰 외 confirm 시간 제한 없음)
  • RabbitMqService.cs:96-106 (NotifySavedAsync — 예외만 삼키고 대기는 그대로)
  • server/http/Service/WriteBackService.cs:41-57 (Post → 같은 PublishAsync, Redis 기록 뒤 write-back 발행)
  • Repository.RedisHash.cs:198-199 / Repository.RedisValue Set 버퍼: Redis 쓰기 후 _dbExecuteService.Post → SaveChangesAsync가 요청 스레드에서 대기
  • 호출처(락 안 NotifySaved 예): ClanController.cs:1213-1268 (money — distributed lock 유지한 채 SaveChanges→NotifySaved), GroupService.cs:180-227 (그룹 생성), StorageService.cs:261-269, MailController WriteMails, BanController.cs:42

문제

FB-252(#673)와 같은 패턴이 Internal RabbitMQ에도 있다.

  1. Write-back: Redis-first 저장소의 SaveChangesAsync가 write-back 메시지를 RabbitMqService.PublishAsync로 동기 대기한다. publisher confirm이 무응답이면(쿼럼 과반 상실·디스크/메모리 block·브로커 hang) 예외도 안 나고 요청이 멈춘다. catch는 throw된 경우만 write_back_failure로 간다.
  2. NotifySavedAsync: FB-132 수정으로 publish 예외는 삼키지만, confirm 대기는 그대로다. 문파자금·그룹·보관함·메일 등에서 Redis/DB 반영 뒤에도 응답 전에 기다리고, 문파·그룹은 분산 락을 쥔 채 기다린다.
  3. 둘 다 프로세스 단일 _channelLock이라 한 요청이 confirm에 붙잡히면 같은 파드의 다른 Internal publish(킥·공지·다른 저장)도 줄을 선다.

로그 브로커(FB-252)와는 별 채널(RabbitMQ:Internal)이지만, 장애 조건·락·무제한 confirm은 동일하다.

영향

  • Internal MQ 정지 → 캐릭터/문파/밴 등 Redis write-back이 포함된 SaveChanges가 hang → 로그인 저장·문파 입출금·그룹 조작·보관함 생성이 게임 HTTP 제한을 넘겨 실패.
  • 문파·그룹 락을 쥔 채 NotifySaved가 멈추면 같은 문파/그룹의 다른 요청까지 연쇄 대기.
  • Redis에는 이미 반영된 뒤일 수 있어(문파자금 RequestId 멱등) 복제보다 가용성 정지가 핵심(FB-132와 직교).

수정 방향

  1. Write-back: 요청 경로에서 confirm 대기하지 않기. 상한 있는 Channel에 적재 후 BackgroundService가 발행(실패 시 기존 write_back_failure 경로). 최소안: Publish에 1~2초 CancellationToken·짧은 연결 타임아웃.
  2. NotifySaved: 저장 완료 응답을 먼저 돌리고 알림은 fire-and-forget/outbox(또는 같은 짧은 타임아웃). 분산 락은 SaveChanges 직후·NotifySaved 전에 해제.
  3. FB-252(LogService)와 같이 publisher confirm tracking을 요청 경로에서 끄거나, confirm에 명시 데드라인을 둔다.

Activity

  1. boyism80 commented on Oct 16, 2026

    @boyism80
    OwnerAuthor

    [FB 리뷰어]
    ce5d1119d에서 RabbitMqService가 Channel+HostedService 백그라운드 publish로 바뀌어 요청 경로의 publisher confirm 대기가 제거됐습니다. WriteBack은 FullMode=Wait·onFailure→RecordFailure로 런타임 실패는 기록됩니다. SaveChanges/NotifySaved hang(본문)은 해결로 닫습니다. 종료 시 인메모리 큐 유실·onFailure 미호출은 별도 FB-263으로 추적합니다.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions