Last active
October 9, 2019 15:32
-
-
Save Pooh3Mobi/6093c658fb7ab731815692afc33b72fd to your computer and use it in GitHub Desktop.
失敗したらMAXまでリトライし、成功したら次の処理を行うKotlinコード、失敗の情報は保持する
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
package com.example.forloop | |
sealed class Result<T, E> { | |
data class Success<T, E>(val t: T) : Result<T, E>() | |
data class Failure<T, E>(val e: E) : Result<T, E>() | |
} | |
sealed class MultiResult<T, E> { | |
data class Success<T, E>(val t: T, val ers: List<E>?) : MultiResult<T, E>() | |
data class Failures<T, E>(val msg: String, val ers: List<E>) : MultiResult<T, E>() | |
} | |
sealed class Step<out T, E> { | |
data class Done<out T, E>(val t: T, val ers: List<E>?) : Step<T, E>() | |
data class Continue<out T, E>(val ers: List<E>) : Step<T, E>() | |
data class Error<out T, E>( | |
val msg: String, | |
val ers: List<E> | |
) : Step<T, E>() | |
} | |
fun <T> (() -> T).runCatching(): Result<T, Throwable> = | |
try { | |
Result.Success(this()) | |
} catch (e: Exception) { | |
Result.Failure(e) | |
} | |
fun <T> repeat( | |
max: Int = 1, | |
msg: (List<Throwable>) -> String = { "" }, | |
lambda: () -> T | |
): MultiResult<T, Throwable> { | |
return (1..max).asSequence() | |
.fold( | |
initial = Step.Continue<T, Throwable>(listOf()) as Step<T, Throwable>, | |
operation = { acc, repeatIndex: Int -> | |
fun runAndNextStep(continueStep: Step.Continue<T, Throwable>): Step<T, Throwable> = | |
when (val res = lambda.runCatching()) { | |
is Result.Success -> Step.Done(res.t, continueStep.ers) | |
is Result.Failure -> { | |
val concat = continueStep.ers + res.e | |
if (repeatIndex >= max) Step.Error(msg(concat), concat) | |
else Step.Continue(concat) | |
} | |
} | |
if (acc is Step.Continue<T, Throwable>) { | |
runAndNextStep(acc) | |
} else { | |
acc | |
} | |
} | |
) | |
.takeIf { | |
it is Step.Done<T, Throwable> || it is Step.Error<T, Throwable> | |
} | |
.let { step -> | |
return@let when (step) { | |
is Step.Done -> MultiResult.Success(step.t, step.ers) | |
is Step.Error -> MultiResult.Failures(step.msg, step.ers) | |
else -> throw IllegalArgumentException() | |
} | |
} | |
} |
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
package com.example.forloop | |
import java.io.IOException | |
data class FileData(val number: Int) | |
fun main(args: Array<String>) { | |
val fileOperation = { fileData: FileData -> | |
repeat( | |
max = 3, | |
msg = { ers ->"$fileData has some errors: $ers"}, | |
lambda = { treatSomethingAboutFile(fileData) } | |
) | |
} | |
val resultToBoolean = { res: MultiResult<Unit, Throwable> -> | |
when(res) { | |
is MultiResult.Success -> true | |
is MultiResult.Failures -> false | |
} | |
} | |
val sendResult = { file: FileData, isSuccess: Boolean -> | |
if (isSuccess) sendSuccess(file) | |
else sendFailure(file) | |
} | |
val files = createFileDataList(28) | |
val res: List<Pair<FileData, Boolean>> = files.asSequence() | |
.map(fileOperation) | |
.map(resultToBoolean) | |
.mapIndexed { index, isSuccess -> | |
val file = files[index] | |
sendResult(file, isSuccess) | |
file to isSuccess | |
}.toList() | |
println(res) | |
} | |
private fun sendSuccess(file: FileData) { | |
println("$file is Success") | |
} | |
private fun sendFailure(file: FileData) { | |
println("$file is Failure") | |
} | |
private fun createFileDataList(max: Int) = | |
(0..max).map { FileData(it) } | |
private fun treatSomethingAboutFile(fileData: FileData) { | |
Thread.sleep(500) | |
// 疑似的に5つに1つの割合で失敗するデータ的なやつ | |
if (fileData.number%5 == 0) { | |
println("$fileData IOE!") | |
throw IOException() | |
} | |
} |
作業中コード
fun <T> repeat2(
max: Int = 1,
msg: (Any) -> String = {""},
lambda: () -> T
) : MultiResult<T, Throwable> {
var step: Step2<T, Throwable> = Step2.Cont(Input<Throwable>(null, null))
for (i in 0..max) {
when (step) {
is Step2.Cont -> {
step = process2(
i, max-1, step,
{ lambda.toThrowableResult() },
msg
)
}
is Step2.Res -> return MultiResult.Success(step.t, step.e)
}
}
throw IllegalArgumentException()
}
sealed class Step2<T, E> {
data class Cont<T, E>(val input: Input<E>) : Step2<T, E>()
data class Res<T, E>(val t: T? = null, val e: List<E>?, val msg: String? = null) : Step2<T, E>()
}
data class Input<V> (val v: V?, val input: Input<V>?) {
fun toList(): ArrayList<out V> = recur(this, arrayListOf())
}
private tailrec fun <V> recur(cur: Input<V>, l: ArrayList<V>): ArrayList<V> {
val cv: V? = cur.v
if (cv != null) l.add(cv)
return if (cur.input == null) { l } else { recur(cur.input, l) }
}
fun <T, E> process2(
i: Int, max: Int, cnt: Step2.Cont<T, E>,
lambda: () -> Result<T, E>,
msg: (Any) -> String
): Step2<T, E> {
val res = lambda()
return when (res) {
is Result.Success -> Step2.Res(res.t, cnt.input.toList())
is Result.Failure -> {
val concat = Input(res.e, cnt.input)
val list = concat.toList()
if (i >= max) {
Step2.Res(
e = list,
msg = msg(list)
)
} else {
Step2.Cont(concat)
}
}
}
}
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Log:
FileData(number=0) IOE!
FileData(number=0) IOE!
FileData(number=0) IOE!
FileData(number=0) is Failure
FileData(number=1) is Success
FileData(number=2) is Success
FileData(number=3) is Success
FileData(number=4) is Success
FileData(number=5) IOE!
FileData(number=5) IOE!
FileData(number=5) IOE!
FileData(number=5) is Failure
FileData(number=6) is Success
FileData(number=7) is Success
FileData(number=8) is Success
FileData(number=9) is Success
FileData(number=10) IOE!
FileData(number=10) IOE!
FileData(number=10) IOE!
FileData(number=10) is Failure
FileData(number=11) is Success
FileData(number=12) is Success
FileData(number=13) is Success
FileData(number=14) is Success
FileData(number=15) IOE!
FileData(number=15) IOE!
FileData(number=15) IOE!
FileData(number=15) is Failure
FileData(number=16) is Success
FileData(number=17) is Success
FileData(number=18) is Success
FileData(number=19) is Success
FileData(number=20) IOE!
FileData(number=20) IOE!
FileData(number=20) IOE!
FileData(number=20) is Failure
FileData(number=21) is Success
FileData(number=22) is Success
FileData(number=23) is Success
FileData(number=24) is Success
FileData(number=25) IOE!
FileData(number=25) IOE!
FileData(number=25) IOE!
FileData(number=25) is Failure
FileData(number=26) is Success
FileData(number=27) is Success
FileData(number=28) is Success
[(FileData(number=0), false), (FileData(number=1), true), (FileData(number=2), true), (FileData(number=3), true), (FileData(number=4), true), (FileData(number=5), false), (FileData(number=6), true), (FileData(number=7), true), (FileData(number=8), true), (FileData(number=9), true), (FileData(number=10), false), (FileData(number=11), true), (FileData(number=12), true), (FileData(number=13), true), (FileData(number=14), true), (FileData(number=15), false), (FileData(number=16), true), (FileData(number=17), true), (FileData(number=18), true), (FileData(number=19), true), (FileData(number=20), false), (FileData(number=21), true), (FileData(number=22), true), (FileData(number=23), true), (FileData(number=24), true), (FileData(number=25), false), (FileData(number=26), true), (FileData(number=27), true), (FileData(number=28), true)]
Process finished with exit code 0