Skip to content

Commit 6685c38

Browse files
committed
arrow 2.0.0
1 parent ab3f50a commit 6685c38

File tree

6 files changed

+113
-3
lines changed

6 files changed

+113
-3
lines changed

build.gradle.kts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,10 +67,11 @@ dependencies {
6767
implementation("com.ensody.reactivestate:reactivestate")
6868

6969
// Arrow-kt
70-
val arrow = "1.2.4"
70+
val arrow = "2.0.0"
7171
implementation("io.arrow-kt:arrow-core:$arrow")
7272
implementation("io.arrow-kt:arrow-fx-coroutines:$arrow")
7373
implementation("io.arrow-kt:arrow-autoclose:$arrow")
74+
implementation("io.arrow-kt:arrow-resilience:$arrow")
7475
}
7576

7677
tasks.test {
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package com.hoc081098.kotlin_playground.arrowkt
2+
3+
import arrow.resilience.Schedule
4+
import arrow.resilience.retry
5+
import kotlinx.coroutines.runBlocking
6+
7+
fun main(): Unit = runBlocking {
8+
val recurs: Schedule<Throwable, Long> = Schedule.recurs<Throwable>(3)
9+
10+
recurs.retry {
11+
println(">>> calling...")
12+
throw RuntimeException("Error")
13+
}
14+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
package com.hoc081098.kotlin_playground.arrowkt
2+
3+
import arrow.core.Either
4+
import arrow.resilience.CircuitBreaker
5+
import kotlin.time.Duration.Companion.seconds
6+
import kotlin.time.ExperimentalTime
7+
import kotlinx.coroutines.delay
8+
9+
@ExperimentalTime
10+
suspend fun main(): Unit {
11+
val circuitBreaker = CircuitBreaker(
12+
openingStrategy = CircuitBreaker.OpeningStrategy.Count(2),
13+
resetTimeout = 2.seconds,
14+
exponentialBackoffFactor = 1.2,
15+
maxResetTimeout = 60.seconds,
16+
)
17+
18+
// normal operation
19+
circuitBreaker.protectOrThrow { "I am in Closed: ${circuitBreaker.state()}" }.also(::println)
20+
21+
// simulate service getting overloaded
22+
Either.catch {
23+
circuitBreaker.protectOrThrow { throw RuntimeException("Service overloaded") }
24+
}.also(::println)
25+
Either.catch {
26+
circuitBreaker.protectOrThrow { throw RuntimeException("Service overloaded") }
27+
}.also(::println)
28+
circuitBreaker.protectEither { }
29+
.also { println("I am Open and short-circuit with ${it}. ${circuitBreaker.state()}") }
30+
31+
println(">>> state should be Open: ${circuitBreaker.state()}")
32+
// simulate reset timeout
33+
println("Service recovering . . .").also { delay(2500) }
34+
println(">>> state should be HalfOpen: ${circuitBreaker.state()}")
35+
36+
// simulate test request success
37+
circuitBreaker.protectOrThrow {
38+
"I am running test-request in HalfOpen: ${circuitBreaker.state()}"
39+
}.also(::println)
40+
println("I am back to normal state closed ${circuitBreaker.state()}")
41+
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
package com.hoc081098.kotlin_playground.arrowkt
2+
3+
import arrow.core.Either
4+
import arrow.resilience.CircuitBreaker
5+
import arrow.resilience.Schedule
6+
import arrow.resilience.retry
7+
import kotlin.time.Duration.Companion.seconds
8+
import kotlin.time.ExperimentalTime
9+
import kotlinx.coroutines.delay
10+
11+
@ExperimentalTime
12+
suspend fun main(): Unit {
13+
suspend fun apiCall(): Unit {
14+
println("apiCall . . .")
15+
delay(100)
16+
throw RuntimeException("Overloaded service")
17+
}
18+
19+
val circuitBreaker = CircuitBreaker(
20+
openingStrategy = CircuitBreaker.OpeningStrategy.Count(2),
21+
resetTimeout = 2.seconds,
22+
exponentialBackoffFactor = 1.2,
23+
maxResetTimeout = 60.seconds,
24+
)
25+
26+
suspend fun <A> resilient(schedule: Schedule<Throwable, *>, f: suspend () -> A): A =
27+
schedule.retry {
28+
println(">>> retry...")
29+
circuitBreaker.protectOrThrow {
30+
println(">>> inside protectOrThrow")
31+
f()
32+
}
33+
}
34+
35+
// simulate getting overloaded
36+
Either.catch {
37+
resilient(Schedule.recurs(5), ::apiCall)
38+
}.let { println("recurs(5) apiCall twice and 4x short-circuit result from CircuitBreaker: $it") }
39+
40+
// simulate reset timeout
41+
delay(2000)
42+
println("CircuitBreaker ready to half-open")
43+
44+
// retry once,
45+
// and when the CircuitBreaker opens after 2 failures
46+
// retry with exponential back-off with same time as CircuitBreaker's resetTimeout
47+
val fiveTimesWithBackOff = Schedule.recurs<Throwable>(1)
48+
.andThen(Schedule.exponential(2.seconds))
49+
.and(Schedule.recurs(5))
50+
51+
Either.catch {
52+
resilient(fiveTimesWithBackOff, ::apiCall)
53+
}.let { println("exponential(2.seconds) and recurs(5) always retries with actual apiCall: $it") }
54+
}

src/main/kotlin/com/hoc081098/kotlin_playground/arrowkt/resource.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package com.hoc081098.kotlin_playground.arrowkt
33
import arrow.fx.coroutines.asFlow
44
import arrow.fx.coroutines.resource
55
import arrow.fx.coroutines.resourceScope
6+
import arrow.fx.coroutines.use
67
import com.hoc081098.solivagant.lifecycle.LenientLifecycleRegistry
78
import com.hoc081098.solivagant.lifecycle.Lifecycle
89
import kotlinx.coroutines.delay

src/main/kotlin/com/hoc081098/state/stateIn.kt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package com.hoc081098.state
22

3-
import arrow.fx.coroutines.continuations.resource
43
import kotlinx.coroutines.CoroutineScope
54
import kotlinx.coroutines.Dispatchers
65
import kotlinx.coroutines.delay
@@ -40,4 +39,4 @@ fun main() = runBlocking {
4039
.launchIn(scope)
4140

4241
delay(2000)
43-
}
42+
}

0 commit comments

Comments
 (0)