forked from GitHub-Mirror/riotX-android
Introduce retry on task executor and use it for pagination
This commit is contained in:
parent
d288fb7c9c
commit
7669a94a64
@ -4,10 +4,10 @@ import android.arch.paging.PagedList
|
||||
import com.zhuinden.monarchy.Monarchy
|
||||
import im.vector.matrix.android.api.MatrixCallback
|
||||
import im.vector.matrix.android.api.session.events.model.EnrichedEvent
|
||||
import im.vector.matrix.android.internal.task.TaskExecutor
|
||||
import im.vector.matrix.android.internal.task.configureWith
|
||||
import im.vector.matrix.android.internal.database.model.ChunkEntity
|
||||
import im.vector.matrix.android.internal.database.query.findAllIncludingEvents
|
||||
import im.vector.matrix.android.internal.task.TaskExecutor
|
||||
import im.vector.matrix.android.internal.task.configureWith
|
||||
import im.vector.matrix.android.internal.util.PagingRequestHelper
|
||||
import java.util.*
|
||||
|
||||
@ -53,6 +53,7 @@ internal class TimelineBoundaryCallback(private val roomId: String,
|
||||
limit = limit)
|
||||
|
||||
paginationTask.configureWith(params)
|
||||
.enableRetry()
|
||||
.dispatchTo(object : MatrixCallback<TokenChunkEvent> {
|
||||
override fun onSuccess(data: TokenChunkEvent) {
|
||||
requestCallback.recordSuccess()
|
||||
|
@ -13,6 +13,7 @@ internal data class ConfigurableTask<PARAMS, RESULT>(
|
||||
val params: PARAMS,
|
||||
val callbackThread: TaskThread = TaskThread.MAIN,
|
||||
val executionThread: TaskThread = TaskThread.IO,
|
||||
val retryCount: Int = 0,
|
||||
val callback: MatrixCallback<RESULT> = object : MatrixCallback<RESULT> {}
|
||||
) : Task<PARAMS, RESULT> {
|
||||
|
||||
@ -33,10 +34,18 @@ internal data class ConfigurableTask<PARAMS, RESULT>(
|
||||
return copy(callback = matrixCallback)
|
||||
}
|
||||
|
||||
fun enableRetry(retryCount: Int = Int.MAX_VALUE): ConfigurableTask<PARAMS, RESULT> {
|
||||
return copy(retryCount = retryCount)
|
||||
}
|
||||
|
||||
fun executeBy(taskExecutor: TaskExecutor): Cancelable {
|
||||
return taskExecutor.execute(this)
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return task.javaClass.name
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,9 +1,11 @@
|
||||
package im.vector.matrix.android.internal.task
|
||||
|
||||
import arrow.core.Try
|
||||
import im.vector.matrix.android.api.util.Cancelable
|
||||
import im.vector.matrix.android.internal.util.CancelableCoroutine
|
||||
import im.vector.matrix.android.internal.util.MatrixCoroutineDispatchers
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import timber.log.Timber
|
||||
@ -15,14 +17,36 @@ internal class TaskExecutor(private val coroutineDispatchers: MatrixCoroutineDis
|
||||
|
||||
val job = GlobalScope.launch(task.callbackThread.toDispatcher()) {
|
||||
val resultOrFailure = withContext(task.executionThread.toDispatcher()) {
|
||||
Timber.v("Executing ${task.javaClass} on ${Thread.currentThread().name}")
|
||||
Timber.v("Executing $task on ${Thread.currentThread().name}")
|
||||
retry(task.retryCount) {
|
||||
task.execute(task.params)
|
||||
}
|
||||
}
|
||||
resultOrFailure.fold({ task.callback.onFailure(it) }, { task.callback.onSuccess(it) })
|
||||
}
|
||||
return CancelableCoroutine(job)
|
||||
}
|
||||
|
||||
private suspend fun <T> retry(
|
||||
times: Int = Int.MAX_VALUE,
|
||||
initialDelay: Long = 100, // 0.1 second
|
||||
maxDelay: Long = 10_000, // 10 second
|
||||
factor: Double = 2.0,
|
||||
block: suspend () -> Try<T>): Try<T> {
|
||||
|
||||
var currentDelay = initialDelay
|
||||
repeat(times - 1) {
|
||||
val blockResult = block()
|
||||
if (blockResult.isSuccess()) {
|
||||
return blockResult
|
||||
} else {
|
||||
delay(currentDelay)
|
||||
currentDelay = (currentDelay * factor).toLong().coerceAtMost(maxDelay)
|
||||
}
|
||||
}
|
||||
return block()
|
||||
}
|
||||
|
||||
private fun TaskThread.toDispatcher() = when (this) {
|
||||
TaskThread.MAIN -> coroutineDispatchers.main
|
||||
TaskThread.COMPUTATION -> coroutineDispatchers.computation
|
||||
|
@ -1,24 +0,0 @@
|
||||
package im.vector.matrix.android.internal.util
|
||||
|
||||
import arrow.core.Try
|
||||
import kotlinx.coroutines.delay
|
||||
|
||||
suspend fun <T> retry(
|
||||
times: Int = Int.MAX_VALUE,
|
||||
initialDelay: Long = 100, // 0.1 second
|
||||
maxDelay: Long = 10_000, // 10 second
|
||||
factor: Double = 2.0,
|
||||
block: suspend () -> Try<T>): Try<T> {
|
||||
|
||||
var currentDelay = initialDelay
|
||||
repeat(times - 1) {
|
||||
val blockResult = block()
|
||||
if (blockResult.isSuccess()) {
|
||||
return blockResult
|
||||
} else {
|
||||
delay(currentDelay)
|
||||
currentDelay = (currentDelay * factor).toLong().coerceAtMost(maxDelay)
|
||||
}
|
||||
}
|
||||
return block()
|
||||
}
|
Loading…
Reference in New Issue
Block a user