Skip to content

Commit

Permalink
Lager en retry-dingseboms 🔄
Browse files Browse the repository at this point in the history
  • Loading branch information
fraadsbrandth committed Feb 9, 2024
1 parent 41e436f commit 24d5802
Show file tree
Hide file tree
Showing 5 changed files with 113 additions and 1 deletion.
4 changes: 4 additions & 0 deletions retry/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Retry
================

En dingseboms som retryer ting
3 changes: 3 additions & 0 deletions retry/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
dependencies {
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3")
}
33 changes: 33 additions & 0 deletions retry/src/main/kotlin/com/github/navikt/tbd_libs/retry/Retry.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package com.github.navikt.tbd_libs.retry

import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.delay
import kotlinx.coroutines.runBlocking
import java.time.Duration
import java.time.Duration.ofMillis

suspend inline fun <T> retry(
utsettelser: Iterator<Duration> = DefaultUtsettelser(),
avbryt: (throwable: Throwable) -> Boolean = { false },
block: () -> T
): T {
while (utsettelser.hasNext()) {
try { return block() } catch (t: Throwable) {
if (t is CancellationException || avbryt(t)) throw t
}
delay(utsettelser.next().toMillis())
}
return block()
}

inline fun <T> retryBlocking(
utsettelser: Iterator<Duration> = DefaultUtsettelser(),
crossinline avbryt: (throwable: Throwable) -> Boolean = { false },
crossinline block: () -> T
) = runBlocking { retry(utsettelser, avbryt, block) }

class DefaultUtsettelser: Iterator<Duration> {
private val utsettelser = mutableListOf(ofMillis(200), ofMillis(600), ofMillis(1200))
override fun hasNext() = utsettelser.isNotEmpty()
override fun next(): Duration = utsettelser.removeAt(0)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package com.github.navikt.tbd_libs.retry

import kotlinx.coroutines.delay
import kotlinx.coroutines.runBlocking
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.assertThrows

internal class RetryTest {

@Test
fun `Først en test av dingsen`() {
val dings = DingsSomFunkerPåForsøk(4)
assertEquals("En feil på forsøk 1", assertThrows<IllegalStateException> { dings.gjørtingBlocking() }.message)
assertEquals("En feil på forsøk 2", assertThrows<IllegalStateException> { dings.gjørtingBlocking() }.message)
assertEquals("En feil på forsøk 3", assertThrows<IllegalStateException> { dings.gjørtingBlocking() }.message)
assertEquals("Det gikk jo bra på førsøk 4 da", dings.gjørtingBlocking())
}

@Test
fun `Når noe funker med en gang`() {
val dings = DingsSomFunkerPåForsøk(1)
assertEquals("Det gikk jo bra på førsøk 1 da", retryBlocking { dings.gjørtingBlocking() })
}

@Test
fun `Når noe funker med på førsøk 3`() {
val dings = DingsSomFunkerPåForsøk(3)
assertEquals("Det gikk jo bra på førsøk 3 da", retryBlocking { dings.gjørtingBlocking() })
}

@Test
fun `Når noe feiler 4 ganger og vi ikke prøver noe mer`() {
val dings = DingsSomFunkerPåForsøk(5)
assertEquals("En feil på forsøk 4", assertThrows<IllegalStateException> { retryBlocking { dings.gjørtingBlocking() } }.message)
}

@Test
fun `Om det er en spesiell feil som vi ikke vil retrye på så fortsetter vi ei`() {
val dings = DingsSomFunkerPåForsøk(10, feil = { EnfeilViIkkeVilRetrye(it) })
assertEquals(
"For dette her fikses ikke av en retry. Så derfor feiler vi på forsøk 1",
assertThrows<IllegalStateException> { retryBlocking(avbryt = { it is EnfeilViIkkeVilRetrye} ) { dings.gjørtingBlocking() } }.message
)
}

@Test
fun `Når noe funker med på førsøk 3 suspendable`() = runBlocking {
val dings = DingsSomFunkerPåForsøk(3)
assertEquals("Det gikk jo bra på førsøk 3 da", retry { dings.gjørting() })
}

private class DingsSomFunkerPåForsøk(
private val forsøk: Int,
private val feil: (nåværendeForsøk: Int) -> Throwable = { IllegalStateException("En feil på forsøk $it") }
) {
init { check(forsøk >= 1) }
private var nåværendeForsøk = 1

fun gjørtingBlocking(): String {
if (nåværendeForsøk == forsøk) return "Det gikk jo bra på førsøk $nåværendeForsøk da"
throw feil(nåværendeForsøk++)
}
suspend fun gjørting(): String {
delay(1)
return gjørtingBlocking()
}

}

private class EnfeilViIkkeVilRetrye(nåværendeForsøk: Int): IllegalStateException("For dette her fikses ikke av en retry. Så derfor feiler vi på forsøk $nåværendeForsøk")
}
2 changes: 1 addition & 1 deletion settings.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
rootProject.name = "tbd-libs"
include("azure-token-client", "azure-token-client-default", "mock-http-client", "minimal-sts-client", "minimal-soap-client", "postgres-testdatabaser")
include("azure-token-client", "azure-token-client-default", "mock-http-client", "minimal-sts-client", "minimal-soap-client", "postgres-testdatabaser", "retry")

0 comments on commit 24d5802

Please sign in to comment.