Lukasz Kalnik
10/19/2022, 12:11 PMarrow-fx-stm
dependency?simon.vergauwen
10/19/2022, 12:12 PMio.arrow-kt:arrow-fx-stm:1.1.3
?Lukasz Kalnik
10/19/2022, 12:12 PMLukasz Kalnik
10/19/2022, 12:12 PMLukasz Kalnik
10/19/2022, 12:13 PMsimon.vergauwen
10/19/2022, 12:13 PMLukasz Kalnik
10/19/2022, 12:13 PMsimon.vergauwen
10/19/2022, 12:14 PMsimon.vergauwen
10/19/2022, 12:14 PMsimon.vergauwen
10/19/2022, 12:14 PMLukasz Kalnik
10/19/2022, 12:16 PMarrow-fx-coroutines
should be enough for my use case.simon.vergauwen
10/19/2022, 12:19 PMSchedule
should be perfect for that use-case.Lukasz Kalnik
10/19/2022, 12:19 PMsimon.vergauwen
10/19/2022, 12:19 PMSchedule
, so if you have any feedback let me know 🙏simon.vergauwen
10/19/2022, 12:19 PMLukasz Kalnik
10/19/2022, 12:27 PMEither<CallError, T>
and I want to retry it as long as the result is a Left<HttpError>
with code 403
(HttpError
is a child of CallError
). I want to retry with exponential backoff for 60 seconds and then give up with some error.simon.vergauwen
10/19/2022, 12:37 PM@OptIn(ExperimentalTime::class)
fun <A> schedule(): Schedule<Either<HttpError, A>, Either<HttpError, A>> =
Schedule.exponential<Either<HttpError, A>>(1.seconds)
.check { either: Either<HttpError, A>, duration ->
(either as? Either.Left<HttpError>)?.value?.code == 403 && duration < 60.seconds
}.zipRight(Schedule.identity())
Lukasz Kalnik
10/19/2022, 12:38 PMsimon.vergauwen
10/19/2022, 12:39 PMschedule<A>().repeat { call() }
Lukasz Kalnik
10/19/2022, 12:39 PMLukasz Kalnik
10/19/2022, 12:40 PMrepeat()
is only for calls that succeeded, I was wondering if there is analogous retry()
for calls that fail (as the documentation hints that this is a different behavior).simon.vergauwen
10/19/2022, 12:40 PMcall
according to the schedule. So any other HttpError
would be considered "succes" and won't be repeated.
It will also only repeat exponentially with a limit of 60.seconds
, but you could also add and(Schedule.recurs(n))
if you'd wanted to limit to a certain amount of retriesLukasz Kalnik
10/19/2022, 12:41 PMsimon.vergauwen
10/19/2022, 12:43 PMrepeat(1.seconds, Policy.Exponential())
.retry<Either<HttpError, A>> {
val res: Either<HttpError, A> = call()
ensure(res.leftOrNull()?.code != 403) { ??? }
}
Lukasz Kalnik
10/19/2022, 12:44 PMsimon.vergauwen
10/19/2022, 12:45 PMLukasz Kalnik
10/19/2022, 12:46 PMsimon.vergauwen
10/19/2022, 12:47 PMLukasz Kalnik
10/19/2022, 12:48 PMLukasz Kalnik
10/19/2022, 1:01 PMLeft<HttpError>
because of type erasure:
.check { either: Either<CallError, AirConnectorSystem>, duration ->
either is Left<*> &&
either.value is HttpError &&
(either.value as HttpError).code == 403 &&
duration < 60.seconds
}
Lukasz Kalnik
10/19/2022, 1:02 PMHttpError
is a child of CallError
(I think I didn't mention that in my initial question actually).simon.vergauwen
10/19/2022, 1:10 PMLukasz Kalnik
10/19/2022, 1:11 PMzipRight()
for meLukasz Kalnik
10/19/2022, 1:13 PMretry()
function which calls zipRight(Schedule.identity()
.repeat() would be a way to make it easier?
I'm not sure if it's semantically correct though, but something along those lines.
I think many times when retrying the users will not be actually interested in the output of the Schedule
, but in the last (successful) output of the actual function being repeated.simon.vergauwen
10/19/2022, 1:17 PMzipRight(Schedule.identity())
so it makes more sense to offer a separate retryOutput
functions for the very few times you want it.Lukasz Kalnik
10/19/2022, 1:17 PMLukasz Kalnik
10/19/2022, 1:18 PMsimon.vergauwen
10/19/2022, 1:19 PMLukasz Kalnik
10/19/2022, 1:19 PM