Jörg Winter
10/16/2023, 5:48 AMsuspend fun collectData() {
parZip(
{ catch { fetchFromHttp1() } },
{ catch { fetchFromHttp2() } },
{ catch { fetchFromHttp3() } }
) { result1, result2, result3 ->
val result = zipOrAccumulate(result1, result2, result3) { r1, r2, r3 ->
dbRepository.save(Entity(r1, r2, r3))
}
result.onLeft {
log.error(it.map { it.message }.joinToString("\n", "\n"))
}
}
}
simon.vergauwen
10/16/2023, 6:00 AMparZipOrAccumulate
.
suspend fun collectData() {
parZipOrAccumulate(
{ catch { fetchFromHttp1() }.bind() },
{ catch { fetchFromHttp2() }.bind() },
{ catch { fetchFromHttp3() }.bind() }
) { r1, r2, r3 ->
dbRepository.save(Entity(r1, r2, r3))
.onLeft {
log.error(it.map { it.message }.joinToString("\n", "\n"))
}
}
}
Jörg Winter
10/16/2023, 6:04 AMAlejandro Serrano.Mena
10/16/2023, 7:00 AMJörg Winter
10/16/2023, 7:06 AMsimon.vergauwen
10/16/2023, 8:06 AMRaise<E>
. https://apidocs.arrow-kt.io/arrow-fx-coroutines/arrow.fx.coroutines/par-zip-or-accumul[…]A,%20B,%20C,%20D,%20F,%20G,%20H,%20I,%20J)%20-%3E%20K):%20K
I think you need to call:
suspend fun collectData() = either {
parZipOrAccumulate(
{ catch { fetchFromHttp1() }.bind() },
{ catch { fetchFromHttp2() }.bind() },
{ catch { fetchFromHttp3() }.bind() }
) { r1, r2, r3 ->
dbRepository.save(Entity(r1, r2, r3))
.onLeft {
log.error(it.map { it.message }.joinToString("\n", "\n"))
}
}
}
bind
that has been deprecated but it's from a long long time ago. There was an object ResultEffect
from the pre-1.x DSLs, that accidentally leaked into the public API 😕 Since it's an object
it can be top-level imported, and it's basically Either<Throwable, A>#getOrThrow
.
We probably should've changed it to HIDDEN
in 1.2.xJörg Winter
10/16/2023, 12:23 PMsimon.vergauwen
10/16/2023, 12:32 PMJörg Winter
10/16/2023, 1:01 PMimport arrow.core.Either.Companion.catch
import arrow.core.raise.either
import arrow.fx.coroutines.parZipOrAccumulate
import org.springframework.stereotype.Service
@Service
class DataCollectionService(
) {
suspend fun collectAndSave() {
either {
parZipOrAccumulate(
{ catch { fetchSomeHttp1() }.bind() },
{ catch { fetchSomeHttp2() }.bind() },
{ catch { fetchSomeHttp3() }.bind() }
) { result1: String, result2: String, result3: String ->
// TODO what ever with results
}
}
}
private fun fetchSomeHttp1(): String {
return "r1"
}
private fun fetchSomeHttp2(): String {
return "r2"
}
private fun fetchSomeHttp3(): String {
return "r3"
}
}
simon.vergauwen
10/16/2023, 1:51 PMeither<Throwable, A> { }
Jörg Winter
10/16/2023, 3:58 PMeither<Throwable, Unit> {
parZipOrAccumulate(
{ throwable, throwable2 -> RuntimeException(throwable.message + throwable2.message) },
{ catch { fetchSomeHttp1() }.bind() },
{ catch { fetchSomeHttp2() }.bind() },
{ catch { fetchSomeHttp3() }.bind() }
) { result1, result2, result3 ->
// some side-effect of type Unit
}
}.onLeft { left -> log.error(left.message) }
🎉simon.vergauwen
10/17/2023, 6:29 AMeither<NonEmptyList<Throwable>, Unit> { }
you don't need to extra lambda,
but if you want to stick to throwable that is better. Although I'd use throwable.apply { addSuppressed(throwable2) }