fix: 채팅 재구독 세대 가드 — 동기 closed 재진입 - #308
Merged
Merged
Conversation
#305 가 알림 채널(RealtimeService)의 백오프 사다리는 가져왔는데 같이 있어야 할 세대 카운터를 빠뜨렸다. unsubscribe → removeChannel 은 그 채널의 subscribe 콜백에 closed 를 한 번 더 발화시킨다. 소켓이 이미 끊겨 있으면 — 끊김 복구의 대부분이 이 경우다 — realtime_channel 의 `if (!canPush) leavePush.trigger('ok')` 를 타 **동기로** 되돌아온다(canPush = isConnected && isJoined). _resubscribe 는 그 unsubscribe 뒤에 대입되므로 재진입 시점엔 아직 null 이라 재진입 가드를 그냥 통과한다. 결과: ① 재진입이 타이머 T1 을 잡고, 바깥이 이어서 T2 로 덮어쓴다(cancel 없이). 둘 다 발화해 채널이 둘이 되고 하나는 주인 없이 남는다. 샌 채널의 이후 이벤트가 다시 재구독을 부른다. ② 소켓이 살아 있으면 leave ack 의 closed 가 재구독 **뒤에** 도착해 멀쩡한 새 채널을 파괴한다 — refill 이 빈손이면 _attempt 리셋도 없어 30초 간격 재구독이 영구히 돈다. RealtimeService 가 정확히 같은 함정을 _gen 으로 막고 있다. 그 패턴을 그대로 쓴다 — 채널 identity 비교는 콜백이 대입 전에 발화할 수 있어 세대 카운터가 안전하다. t: 대역이 동기 재발화를 흉내 낸다. 수정 전 2개 실패(각각 구독 3회), 수정 후 통과. 첫 테스트는 2.6초를 기다린다 — 이중 예약된 두 타이머는 _attempt 가 달라 1초·2초로 갈리므로 1.4초만 보면 버그를 놓친다. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
전체 라인 커버리지: 20.5% (4291/20903) 이 PR 의 변경 파일:
|
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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
#305 후속. 백오프 사다리는
RealtimeService에서 가져왔는데 같이 있어야 할 세대 카운터가 빠졌다.무엇이 문제인가
unsubscribe()→removeChannel은 그 채널의 subscribe 콜백에closed를 한 번 더 발화시킨다. 소켓이 이미 끊겨 있으면 — 끊김 복구의 대부분이 이 경우다 — 동기로 되돌아온다:_resubscribe는 그unsubscribe뒤에 대입되므로 재진입 시점엔 아직null— 재진입 가드를 그냥 통과한다.closed가 재구독 뒤에 도착해 멀쩡한 새 채널을 파괴. refill 이 빈손이면_attempt리셋도 없어 30초 간격 재구독이 영구히 돈다RealtimeService는 정확히 이 함정을_gen으로 막고 있다(realtime_service.dart:50주석이 이유를 적어 뒀다). 사다리만 이식되고 가드가 빠진 셈.고치는 방법
같은
_gen패턴. 채널 identity 비교 대신 세대 카운터를 쓴 이유는 콜백이_channel대입 전에 발화할 수 있어서다.검증
대역이 동기 재발화를 흉내 낸다 — 이게 없으면 테스트가 버그를 못 잡는다.
flutter analyze클린, 전체 328개 통과첫 테스트는 2.6초를 기다린다. 이중 예약된 두 타이머는
_attempt가 달라 1초·2초로 갈리므로 1.4초만 보면 버그가 있어도 통과해 버린다 (처음 이 함정에 빠졌다).🤖 Generated with Claude Code