Created
April 20, 2020 13:59
-
-
Save fluidsonic/be1cf0329ecc1994cf911beefdcb0631 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@file:OptIn(ExperimentalTime::class) | |
import kotlinx.coroutines.* | |
import kotlin.time.* | |
suspend fun main() { | |
coroutineScope { | |
println("Launching tasks…") | |
val printTask = PrintDelayedTask.launchIn(this, delay = 5.seconds, text = "PrintDelayedTask prints!") | |
val validationTask = ValidationTask.launchIn(this) { isValid -> | |
println("Validation task completed. isValid = $isValid") | |
} | |
println("Tasks launched!") | |
delay(6.seconds) | |
printTask.cancel() | |
println("Waiting for current validation try…") | |
validationTask.waitForCurrentTry() | |
println("Waiting for all tasks to complete…") | |
} | |
println("All done!") | |
} | |
interface Task { | |
fun cancel() | |
} | |
abstract class AbstractTask(scope: CoroutineScope) : Task { | |
protected val job: Job | |
init { | |
// probably a bad idea as the subclass may not be fully initialized yet | |
job = scope.launch { run() } | |
} | |
override fun cancel() { | |
job.cancel() | |
} | |
protected abstract suspend fun run() | |
} | |
class PrintDelayedTask private constructor( | |
scope: CoroutineScope, | |
private val delay: Duration, | |
private val text: String | |
) : AbstractTask(scope) { | |
override suspend fun run() { | |
delay(delay) | |
println(text) | |
} | |
companion object { | |
fun launchIn( | |
scope: CoroutineScope, | |
delay: Duration, | |
text: String | |
) = | |
PrintDelayedTask(scope = scope, delay = delay, text = text) | |
} | |
} | |
class ValidationTask private constructor( | |
scope: CoroutineScope, | |
private val completion: (isValid: Boolean) -> Unit | |
) : AbstractTask(scope) { | |
private var currentTryJob = Job() | |
override suspend fun run() { | |
var isValid: Boolean | |
var tryNumber = 0 | |
while (true) { | |
tryNumber += 1 | |
try { | |
isValid = someValidation(tryNumber) | |
break | |
} catch (e: Exception) { | |
// oh no! | |
} | |
println("Validation try $tryNumber failed. Retrying…") | |
currentTryJob.complete() | |
currentTryJob = Job() | |
delay(6.seconds) | |
} | |
currentTryJob.complete() | |
if (!job.isCancelled) | |
completion(isValid) | |
} | |
suspend fun waitForCurrentTry() { | |
currentTryJob.join() | |
} | |
companion object { | |
fun launchIn( | |
scope: CoroutineScope, | |
completion: (isValid: Boolean) -> Unit | |
) = | |
ValidationTask(scope = scope, completion = completion) | |
} | |
} | |
suspend fun someValidation(tryNumber: Int): Boolean { | |
delay(1.seconds) | |
if (tryNumber < 3) | |
error("Nice try!") | |
return true | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment