【问题标题】:How to retry a request with different input?如何重试具有不同输入的请求?
【发布时间】:2021-10-22 14:13:30
【问题描述】:

目标是使用不同的输入数据进行重试。

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)

如何修改retry 以重试不同的上游(请求不同的查询参数)和 10 次尝试?

【问题讨论】:

  • 一个叫“checkIfNameIsAvailable”的人从哪里来的?

标签: ios swift combine


【解决方案1】:

您可以使用一些高阶函数来实现目标。

如下所示:

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()
    }
}

该函数将重试次数和发布者构建器闭包作为参数。这为您在重试路径上生成新发布者提供了灵活性,因为每次重试时都会调用关闭:

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

【讨论】:

  • 谢谢你,帮助
【解决方案2】:

您不能为此使用retry。这不是retry 所做的。

这是一个不同的策略:

  1. 发布一个十元素序列。
  2. 将这些元素中的每一个都转换为一个查询。
  3. 将每个查询平面映射到查询结果的发布者中。
  4. 获取平面地图的单元素前缀。

因此:

func generateRandomName(seed: Int) -> String {
    return "name\(seed)"
}

struct NameTakenError: Error { }

func availableNamePublisher(name: String) -> AnyPublisher<String, Error> {
    print("checking availability of \(name)")
    if
        let digit = name.last?.wholeNumberValue,
        digit > 3
    {
        return Result.success(name).publisher.eraseToAnyPublisher()
    } else {
        return Result.failure(NameTakenError()).publisher.eraseToAnyPublisher()
    }
}

let ticket = (0 ..< 10).publisher
    .map { i in generateRandomName(seed: i) }
    .flatMap(maxPublishers: .max(1)) { name in
        availableNamePublisher(name: name)
            .catch { _ in Empty() }
    }
    .prefix(1)
    .sink(
        receiveCompletion: { print("completion: \($0)") },
        receiveValue: { print("available name: \($0)") }
    )

输出:

checking availability of name0
checking availability of name1
checking availability of name2
checking availability of name3
checking availability of name4
available name: name4
completion: finished

【讨论】:

  • 谢谢你,帮助
猜你喜欢
  • 1970-01-01
  • 2017-07-24
  • 1970-01-01
  • 1970-01-01
  • 2020-02-20
  • 1970-01-01
  • 2016-04-10
  • 1970-01-01
  • 2016-10-21
相关资源
最近更新 更多