Flutter

| Combine | 12. Retrying and Catching Errors

flutter developer 2024. 5. 15. 17:35

 

 

네트워크 요청이 실패했을 때 바로 사용자에게 실패문구를 띄우는 것보다 2번더 요청해보고 사용자에게 실패문구를 띄우게 할 수 있다. 바로 retry() 연산자를 통해서이다. retry(2) 를 통해 첫번째 시도 + 2번 더요청 했음에도 실패한다면 catch() 연산자를 통해 실패 이벤트를 잡아낸다. 

enum SampleError: Error {
    case somethingWentWrong
}

func fetchData() -> AnyPublisher<String, SampleError> {
    let shouldFail = Bool.random()
    
    if shouldFail {
        print("Fetching data failed, will retry...")
        return Fail(error: SampleError.somethingWentWrong)
            .eraseToAnyPublisher()
    } else {
        return Just("Data loaded successfully")
            .setFailureType(to: SampleError.self)
            .eraseToAnyPublisher()
    }
}

var retryCount = 0

var cancellable = fetchData()
    .handleEvents(receiveSubscription: { _ in
        // 초기 시도를 카운트하지 않고, 재시도 시작 시에만 카운트
        if retryCount > 0 { print("Retry attempt #\(retryCount)") }
        retryCount += 1})
    .retry(3) // 최대 3번 재시도
    .sink(receiveCompletion: { completion in
        switch completion {
        case .finished:
            print("Completed successfully")
        case .failure(let error):
            print("Failed after \(retryCount - 1) retries with error: \(error)")
        }
    }, receiveValue: { value in
        print("Received value: \(value)")
    })

 

먼저 retry연산자를 살펴보자. retry에서 주의할 점은 retry(3) 을 하면 3번 시도하는 것이 아니라 총 4번 시도한다! 첫번째 시도에서 실패하면 3번더 시도한다는 의미이기 때문이다. 

 

enum SampleError2: Error {
    case somethingWentWrong
}

func fetchData2() -> AnyPublisher<String, SampleError2> {
    let shouldFail = Bool.random()
    
    if shouldFail {
        return Fail(error: SampleError2.somethingWentWrong)
            .eraseToAnyPublisher()
    } else {
        return Just("Data loaded successfully")
            .setFailureType(to: SampleError2.self)
            .eraseToAnyPublisher()
    }
}

var cancellable2 = fetchData2()
    .catch { error -> Just<String> in
        print("An error occurred: \(error)")
        return Just("Handling error gracefully, returning fallback data.")
    }
    .sink(receiveCompletion: { completion in
        switch completion {
        case .finished:
            print("Completed successfully or handled error gracefully.")
        case .failure:
            print("Should not see this because errors are handled.")
        }
    }, receiveValue: { value in
        print("Received value: \(value)")
    })

 

catch() 연산자는 단어 그대로 다운스트림 가기전 소비자쪽에서 에러를 잡아내어 또다른 스트림을 열거나 기타 처리를 해줄 수 있는 연산자이다.


https://www.kodeco.com/21773708-intermediate-combine/lessons/5

 

Intermediate Combine, Episode 5: Retrying and Catching Errors

Each publisher gets the ability to retry sending their data if errors are encountered - something commonly seen when working with getting data from the network. The retry() operator can be used to retry the publisher a certain number of times before failin

www.kodeco.com