Конвейер замолкает после одной сетевой ошибки — почему и как catch/retry/replaceError сохраняют его живым?
Этот поисковый конвейер перестаёт выдавать значения после первого упавшего запроса и не восстанавливается, даже когда сеть вернулась.
$query
.flatMap { query in
URLSession.shared.dataTaskPublisher(for: url(query))
.map(\.data)
}
.receive(on: DispatchQueue.main)
.sink(
receiveCompletion: { _ in },
receiveValue: { self.data = $0 }
)
.store(in: &cancellables)
Объясните, почему одна ошибка убивает весь поток, и исправьте так, чтобы сбой не останавливал будущие запросы.
Завершение .failure терминально — оно рвёт подписку, и дальше ничего не течёт. Ставьте retry, catch или replaceError на внутренний publisher внутри flatMap, чтобы ошибка гасилась там, а внешний поток $query продолжал выдавать значения.
- ✗Считают, что завершение
.failureвосстановимо без оператора - ✗Ставят
catch/retryна внешнюю цепочку вместо внутреннего publisher - ✗Думают, что пустое замыкание
receiveCompletionдержит поток живым
- →Почему
catchна внутреннем publisher защищает внешний поток? - →Когда
retryсам по себе хуже, чемretryвместе сcatch?
A failure completion is terminal — it tears down the whole subscription. Keep the error inside the inner publisher so the outer $query stream survives:
$query
.flatMap { query in
URLSession.shared.dataTaskPublisher(for: url(query))
.map(\.data)
.retry(2)
.catch { _ in Just(Data()) } // or replaceError(with:)
}
.receive(on: DispatchQueue.main)
.sink { self.data = $0 }
.store(in: &cancellables)
catch/retry/replaceError on the inner publisher convert or absorb the failure before it reaches the outer subscription, so the outer stream never receives a .failure completion and keeps delivering later queries.