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