Сделайте FirstUseCase ожидаемой suspend-операцией. Только после её успеха запускайте SecondUseCase и ThirdUseCase дочерними корутинами; независимую работу вынесите в отдельный запуск.
Контролируемый асинхронный запуск последовательных UseCase‑операций
Сделайте FirstUseCase ожидаемой suspend-операцией. Только после её успеха запускайте SecondUseCase и ThirdUseCase дочерними корутинами; независимую работу вынесите в отдельный запуск.
Короткий ответ
Что ответить на собеседовании
Подробный разбор
Ответ с пояснениями
Условие
Необходимо построить механизм выполнения набора задач, соблюдая следующую последовательность:
- Сначала запускается FirstUseCase и выполнение останавливается, пока он не завершится успешно.
- После подтверждения успеха FirstUseCase параллельно стартуют SecondUseCase и ThirdUseCase.
- Все остальные действия могут выполняться одновременно без ожидания.
- Результаты (успех/ошибка) обрабатываются через методы .onSuccess и .onFailure.
internal class TaskDelegate @Inject constructor(
private val firstUseCase: UseCaseOne,
private val repository: Storage,
private val secondUseCase: UseCaseTwo,
private val thirdUseCase: UseCaseThree,
private val dataProcessor: DataManager,
) {
fun executeTasks() {
firstUseCase(UseCaseOne.Params())
.onSuccess { repository.updateData() }
dataProcessor.processData()
secondUseCase(UseCaseTwo.Params(timeoutDuration))
.onSuccess { repository.updateData() }
thirdUseCase(Unit)
.onSuccess {
// something
}
.onFailure {
// something
}
}
}
Ответ
Сделайте FirstUseCase ожидаемой suspend-операцией. Только после её успеха запускайте SecondUseCase и ThirdUseCase дочерними корутинами; независимую работу вынесите в отдельный запуск.
Предположим, UseCase возвращают Result, а не лишь регистрируют callback. В управляемом scope запустите две ветви: независимый dataProcessor.processData() и цепочку зависимых операций. Во второй ветви дождитесь firstUseCase, обработайте onFailure и завершите эту ветвь при неуспехе. При успехе обновите repository и запустите secondUseCase/thirdUseCase двумя launch.
Если ошибка второго шага не должна отменять третий, используйте supervisorScope и обработку ошибок каждой ветви. Если отмена нужна — обычный coroutineScope. CancellationException не превращайте в обычную бизнес-ошибку.
Сами onSuccess/onFailure не обеспечивают ожидание произвольного асинхронного API. Если исходные UseCase callback-based, сначала нужен suspend-адаптер с поддержкой отмены. Жизненным циклом общего scope должен владеть экран или другой явно заданный компонент.