如何使用不同的输入重试请求?
How to retry a request with different input?
目标是使用不同的输入数据进行重试。
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 次尝试进行重试?
您不能为此使用 retry
。这不是 retry
所做的。
这里有一个不同的策略:
- 发布一个十元素序列。
- 将每个元素转换为查询。
- 将每个查询平面映射到查询结果的发布者中。
- 取平面图的单元素前缀。
因此:
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: \([=10=])") },
receiveValue: { print("available name: \([=10=])") }
)
输出:
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
您可以使用一些高阶函数来实现目标。
喜欢下面这个:
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)
目标是使用不同的输入数据进行重试。
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 次尝试进行重试?
您不能为此使用 retry
。这不是 retry
所做的。
这里有一个不同的策略:
- 发布一个十元素序列。
- 将每个元素转换为查询。
- 将每个查询平面映射到查询结果的发布者中。
- 取平面图的单元素前缀。
因此:
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: \([=10=])") },
receiveValue: { print("available name: \([=10=])") }
)
输出:
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
您可以使用一些高阶函数来实现目标。
喜欢下面这个:
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)