Search code examples
iosswiftcombine

How to retry a request with different input?


Goal to make retry with different input data.

func generateRandomName() -> Int { ... }

checkIfNameIsAvailable(generateRandomName())
   .retry(10) // <- Makes 10 attempts with same link
   .sink(
       receiveCompletion: { completion in
            },
            receiveValue: { value in
                // Do things
            }
          )
          .store(in: &cancellables)

How can I modify retry to retry with different upstream (request different query parameter) and 10 attempts?


Solution

  • You could use some higher order functions to achieve the goal.

    Like this one below:

    func retry<P: Publisher>(_ times: Int, _ publisherBuilder: @escaping () -> P) -> AnyPublisher<P.Output, P.Failure> {
        if times <= 1 {
            return publisherBuilder().eraseToAnyPublisher()
        } else {
            return publisherBuilder()
                .catch { _ in retry(times-1, publisherBuilder) }
                .eraseToAnyPublisher()
        }
    }
    

    The function takes as arguments a number of retries, and a publisher builder closure. This gives you flexibility when it comes to generating new publishers on the retrial path, as the closure will be invoked every time the retrial is made:

    retry(10) { checkIfNameIsAvailable(generateRandomName()) }
       .sink(
           receiveCompletion: { completion in
                },
                receiveValue: { value in
                    // Do things
                }
              )
              .store(in: &cancellables)