Skip to content

Instantly share code, notes, and snippets.

@Andrew0000
Last active January 13, 2023 12:46
Show Gist options
  • Save Andrew0000/cb621a1a439ba45979bbfcc5dd4855d2 to your computer and use it in GitHub Desktop.
Save Andrew0000/cb621a1a439ba45979bbfcc5dd4855d2 to your computer and use it in GitHub Desktop.
RxRetry with skip retry for 401
import io.reactivex.rxjava3.core.Completable
import io.reactivex.rxjava3.core.Observable
import io.reactivex.rxjava3.core.Single
import timber.log.Timber
import java.util.concurrent.TimeUnit
fun Completable.networkCommonRetrying() =
withRetrying(3, { 4000L * it }, networkRetryCheck)
fun <T : Any> Single<T>.networkCommonRetrying(fallbackValue: T? = null) =
withRetrying(fallbackValue, 3, { 4000L * it }, networkRetryCheck)
fun <T : Any> Observable<T>.networkCommonRetrying(fallbackValue: T? = null) =
withRetrying(fallbackValue, 3, { 4000L * it }, networkRetryCheck)
fun Completable.networkFastRetrying(delay: Long = 2000) =
withRetrying(3, { delay }, networkRetryCheck)
fun <T : Any> Single<T>.networkFastRetrying(fallbackValue: T? = null, delay: Long = 2000) =
withRetrying(fallbackValue, 3, { delay }, networkRetryCheck)
fun <T : Any> Observable<T>.networkFastRetrying(fallbackValue: T? = null, delay: Long = 2000) =
withRetrying(fallbackValue, 3, { delay }, networkRetryCheck)
fun Completable.withRetrying(
tryCnt: Int,
intervalMillis: (tryCnt: Int) -> Long,
retryCheck: (Throwable) -> Boolean = { true }
): Completable = this
.toObservable<Any>()
.withRetrying(null, tryCnt, intervalMillis, retryCheck)
.ignoreElements()
fun <T : Any> Single<T>.withRetrying(
fallbackValue: T?,
tryCnt: Int,
intervalMillis: (tryCnt: Int) -> Long,
retryCheck: (Throwable) -> Boolean = { true }
): Single<T> = this
.toObservable()
.withRetrying(fallbackValue, tryCnt, intervalMillis, retryCheck)
.firstOrError()
fun <T : Any> Observable<T>.withRetrying(
fallbackValue: T?,
tryCnt: Int,
intervalMillis: (tryCnt: Int) -> Long,
retryCheck: (Throwable) -> Boolean = { true }
): Observable<T> {
if (tryCnt <= 0) {
return this
}
return this
.retryWhen { errors ->
errors
.zipWith(
Observable.range(1, tryCnt),
{ th: Throwable, attempt: Int ->
if (retryCheck(th) && attempt < tryCnt) {
Timber.d("[Retrying] attempt: $attempt / $tryCnt")
Observable.timer(intervalMillis(attempt), TimeUnit.MILLISECONDS)
} else {
Timber.d("[Retrying] attempt: $attempt -> Error")
Observable.error(th)
}
}
)
.flatMap { retryCount: Observable<Long> -> retryCount }
}
.let {
if (fallbackValue == null) {
it
} else {
it.onErrorResumeNext { Observable.just(fallbackValue) }
}
}
}
fun <T : Any> Observable<T>.infiniteRetryWithDelay(delay: Long): Observable<T> = this
.onErrorResumeNext { error ->
Observable.timer(delay, TimeUnit.MILLISECONDS)
.flatMap { Observable.error(error) }
}
.retry()
fun <T : Any> Single<T>.infiniteRetryWithDelay(delay: Long): Single<T> = this
.onErrorResumeNext { error ->
Single.timer(delay, TimeUnit.MILLISECONDS)
.flatMap { Single.error(error) }
}
.retry()
private val networkRetryCheck: (Throwable) -> Boolean =
{
val shouldRetry = when {
it.is4xxButNot401() -> false
else -> true
}
shouldRetry
}
private fun Throwable.is4xxButNot401() =
this.tryGetHttpCode().is4xxButNot401()
private fun Int?.is4xxButNot401() =
(this in 400..499) && this != 401
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment