Skip to content

Conversation

@kanghun1121
Copy link
Collaborator

@kanghun1121 kanghun1121 commented Nov 14, 2025

#️⃣ 연관된 이슈

ex) <#1377914257735421952>, <#1377914203255607316>

📝 작업 내용

웹소켓 Unit Test

테스트를 하기 위해서 주입받을 수 있는 테스트 가능한 구조로 변경했습니다. (Mock 객체 주입)

실제 네트워크 통신을 하지 않고 테스트 하기 위해서 MockURLSessionMockWebSocketTask 를 만들어서 사용했습니다.

public class WebSocketClient: NSObject, WebSocketProvider {
    public init(
        url: URL,
        session: URLSessionType = URLSession.shared, // MockURLSession 주입
        stateBroadCaster: AsyncStreamBroadcaster<WebSocket.State> = .init() // MockBroadCaster 주입
    ) {}
}
image

네트워크 백오프

단순히 2초마다 재연결을 시도하는 방식에서 백오프 방식으로 변경했습니다.

변경 전

func reconnect() async {
    try await Task.sleep(for: .seconds(2))
    await connect()
}

변경 후

private var attempts: Int = 0

private func backoff() -> Int {
    attempts += 1
    let base = min(pow(2.0, Double(attempts)) * 100.0, 10000)
    let jitter = Double.random(in: 0.5...1.0)
    
    return Int(base * jitter)
}

/// WebSocket 재연결을 시도합니다.
private func reconnect() async {
    if task?.state == .running || attempts > 10 { return } // 10번 이상 시도했다면 다시 시도하지 않음.
    try? await Task.sleep(for: .milliseconds(backoff()))
    await connect()
}

실제로 네트워크 호출 횟수가 1분 기준으로 약 80% 감소했습니다.

변경 전

스크린샷 2025-11-14 오후 5 55 05

변경 후

스크린샷 2025-11-14 오후 5 50 45

Ping & Pong 재연결 로직 변경

Ping & Pong에서 수신되는 에러가 반드시 재연결이 필요한 네트워크 오류는 아니라는 사실을 확인했습니다.

재연결 해야하는 치명적인 에러인 경우에 한하여 재연결 하도록 로직을 변경했습니다.

/// sendPing(:) 으로부터 받은 에러를 핸들링하는 메소드입니다.
/// - Parameter error: 에러를 전달받습니다.
/// - Returns: 재연결해야 한다면 true를 반환합니다.
private func handlePingError(_ error: Error) -> Bool {
    if let urlError = error as? URLError {
        switch urlError.code { // URLError (네트워크 단절)
            case .notConnectedToInternet, .networkConnectionLost:
                return true
            default:
                return false
        }
    } else if let posixError = error as? POSIXError {
        switch posixError.code { // POSIXError (소켓이 죽음)
            case .EPIPE, .ECONNRESET:
                return true
            default:
                return false
        }
    } else { // 소켓이 정상상태가 아님.
        return true
    }
}

scenePhase 웹소켓 릭 이슈

변경 전

  • 기존 background 모드일 때 해제를 했으나, 전화가 오거나, 네트워크 설정창 갔다 복귀 후에 새로운 연결 생성하여 릭 발

변경 후

  • inactive 일 때 해제 되게 변경

💬 리뷰 요구사항(선택)

리뷰어가 특별히 봐주었으면 하는 부분이 있다면 작성해주세요

@kanghun1121 kanghun1121 requested a review from a team November 14, 2025 11:33
@kanghun1121 kanghun1121 added Test 테스트 관련 작업 Feature 기능 관련 작업 Fix 오류 버그 수정 labels Nov 14, 2025
Copy link
Collaborator

@leekangho0 leekangho0 left a comment

Choose a reason for hiding this comment

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

고생하셨습니다

/// sendPing(:) 으로부터 받은 에러를 핸들링하는 메소드입니다.
/// - Parameter error: 에러를 전달받습니다.
/// - Returns: 재연결해야 한다면 true를 반환합니다.
private func handlePingError(_ error: Error) -> Bool {
Copy link
Collaborator

Choose a reason for hiding this comment

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

핑에서 발생하는 에러에 대해 알아봐야겠네요

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

핑에서 발생하는 에러가 엄청 많아서 재연결할만한 에러를 구분하는게 쉽지 않아보이더라구요🥲

@leekangho0 leekangho0 merged commit 4514075 into dev Nov 14, 2025
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Feature 기능 관련 작업 Fix 오류 버그 수정 Test 테스트 관련 작업

Projects

None yet

Development

Successfully merging this pull request may close these issues.

웹소켓 테스트 웹소켓 Unit Test 진행하기 웹소켓 인터페이스 생성

4 participants