Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

<br>

![version 0.4.7](https://img.shields.io/badge/version-0.4.7-black?labelColor=black&style=flat-square) ![jdk 17](https://img.shields.io/badge/minimum_jdk-17-orange?labelColor=black&style=flat-square) ![load-test](https://img.shields.io/badge/load%20test%2010%2C000%2C000-success-brightgreen?labelColor=black&style=flat-square)
![version 0.4.8](https://img.shields.io/badge/version-0.4.8-black?labelColor=black&style=flat-square) ![jdk 17](https://img.shields.io/badge/minimum_jdk-17-orange?labelColor=black&style=flat-square) ![load-test](https://img.shields.io/badge/load%20test%2010%2C000%2C000-success-brightgreen?labelColor=black&style=flat-square)
![redis--stream](https://img.shields.io/badge/-redis--stream-da2020?style=flat-square&logo=Redis&logoColor=white)

**TPS(6,000)** on my Macbook air m2(default options). _[link](#Test1-TPS)_
Expand Down
1 change: 1 addition & 0 deletions gradle/test.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ dependencies {
testImplementation "org.awaitility:awaitility:${awaitilityVersion}"

testImplementation "io.jsonwebtoken:jjwt-api:0.12.5"
testImplementation "org.springframework.boot:spring-boot-starter-web"
runtimeOnly "io.jsonwebtoken:jjwt-impl:0.12.5"
runtimeOnly "io.jsonwebtoken:jjwt-jackson:0.12.5"
}
3 changes: 3 additions & 0 deletions src/main/kotlin/org/rooftop/netx/api/Exceptions.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package org.rooftop.netx.api

import com.fasterxml.jackson.annotation.JsonIgnoreProperties

class EncodeException(message: String, throwable: Throwable) : RuntimeException(message, throwable)

class DecodeException(message: String, throwable: Throwable) : RuntimeException(message, throwable)
Expand All @@ -16,4 +18,5 @@ class FailedAckSagaException(message: String) : RuntimeException(message)
class ResultTimeoutException(message: String, throwable: Throwable) :
RuntimeException(message, throwable)

@JsonIgnoreProperties(ignoreUnknown = true)
class ResultException(message: String) : RuntimeException(message)
21 changes: 16 additions & 5 deletions src/main/kotlin/org/rooftop/netx/redis/RedisResultHolder.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@ package org.rooftop.netx.redis

import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.module.kotlin.jacksonTypeRef
import org.rooftop.netx.core.Codec
import org.rooftop.netx.api.Result
import org.rooftop.netx.api.ResultException
import org.rooftop.netx.api.ResultTimeoutException
import org.rooftop.netx.core.Codec
import org.rooftop.netx.engine.ResultHolder
import org.rooftop.netx.engine.logging.info
import org.springframework.data.redis.core.ReactiveRedisTemplate
Expand Down Expand Up @@ -73,10 +74,20 @@ internal class RedisResultHolder(
}

override fun <T : Throwable> setFailResult(id: String, result: T): Mono<T> {
val error = Error(
objectMapper.writeValueAsString(result::class.java),
objectMapper.writeValueAsString(result)
)
val error = runCatching {
Error(
type = objectMapper.writeValueAsString(result::class.java),
error = objectMapper.writeValueAsString(result),
)
}.getOrElse {
Error(
type = objectMapper.writeValueAsString(ResultException::class.java),
error = objectMapper.writeValueAsString(
ResultException("Cannot encode fail result to json cause \"${it.message}\"")
),
)
}

val encodedError = objectMapper.writeValueAsString(error)
return reactiveRedisTemplate.opsForList()
.leftPush(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
package org.rooftop.netx.redis

import com.fasterxml.jackson.annotation.JsonAutoDetect
import com.fasterxml.jackson.annotation.JsonCreator
import com.fasterxml.jackson.annotation.JsonIgnore
import com.fasterxml.jackson.annotation.PropertyAccessor
import com.fasterxml.jackson.annotation.*
import com.fasterxml.jackson.databind.DeserializationFeature
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule
Expand Down
12 changes: 12 additions & 0 deletions src/test/kotlin/org/rooftop/netx/engine/OrchestratorConfigurer.kt
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import org.rooftop.netx.engine.OrchestratorTest.Companion.rollbackOrchestratorRe
import org.rooftop.netx.engine.OrchestratorTest.Companion.upChainResult
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.http.HttpStatus
import org.springframework.web.client.HttpClientErrorException
import reactor.core.publisher.Mono
import java.time.Instant

Expand Down Expand Up @@ -317,6 +319,16 @@ internal class OrchestratorConfigurer(
.commit { "" }
}

@Bean(name = ["throwHttpClientErrorExceptionOnStartOrchestrator"])
fun throwHttpClientErrorExceptionOnStartOrchestrator(): Orchestrator<String, String> {
return OrchestratorFactory.instance()
.create<String>("throwHttpClientErrorExceptionOnStartOrchestrator")
.startWithContext({ _, _ ->
throw HttpClientErrorException(HttpStatus.UNAUTHORIZED)
})
.commitWithContext({ _, _ -> "" })
}

fun interface ListOrchestrate :
ContextOrchestrate<List<OrchestratorTest.Home>, List<OrchestratorTest.Home>> {

Expand Down
21 changes: 18 additions & 3 deletions src/test/kotlin/org/rooftop/netx/engine/OrchestratorTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,21 @@ package org.rooftop.netx.engine

import io.jsonwebtoken.JwtException
import io.kotest.assertions.nondeterministic.eventually
import io.kotest.assertions.throwables.shouldThrowExactly
import io.kotest.assertions.throwables.shouldThrowWithMessage
import io.kotest.core.annotation.DisplayName
import io.kotest.core.spec.style.DescribeSpec
import io.kotest.matchers.equality.shouldBeEqualToComparingFields
import io.kotest.matchers.equals.shouldBeEqual
import org.rooftop.netx.api.Orchestrator
import org.rooftop.netx.api.ResultException
import org.rooftop.netx.api.TypeReference
import org.rooftop.netx.meta.EnableSaga
import org.rooftop.netx.redis.RedisContainer
import org.springframework.beans.factory.annotation.Qualifier
import org.springframework.test.context.ContextConfiguration
import org.springframework.test.context.TestPropertySource
import org.springframework.web.client.HttpClientErrorException
import java.time.Instant
import kotlin.time.Duration.Companion.seconds

Expand Down Expand Up @@ -45,6 +48,7 @@ internal class OrchestratorTest(
@Qualifier("throwOnJoinWithContextOrchestrator") private val throwOnJoinWithContextOrchestrator: Orchestrator<List<Home>, List<Home>>,
@Qualifier("throwOnCommitWithContextOrchestrator") private val throwOnCommitWithContextOrchestrator: Orchestrator<List<Home>, List<Home>>,
@Qualifier("throwJwtExceptionOnStartOrchestrator") private val throwJwtExceptionOnStartOrchestrator: Orchestrator<String, String>,
@Qualifier("throwHttpClientErrorExceptionOnStartOrchestrator") private val throwHttpClientErrorExceptionOnStartOrchestrator: Orchestrator<String, String>,
) : DescribeSpec({

describe("numberOrchestrator 구현채는") {
Expand Down Expand Up @@ -259,7 +263,7 @@ internal class OrchestratorTest(
it("해당 예외를 Result에서 throw한다.") {
shouldThrowWithMessage<IllegalArgumentException>("Throw error for test.") {
throwOnStartWithContextOrchestrator.sagaSync(listOf())
.decodeResultOrThrow(object: TypeReference<List<Home>>(){})
.decodeResultOrThrow(object : TypeReference<List<Home>>() {})
}
}
}
Expand All @@ -270,7 +274,7 @@ internal class OrchestratorTest(
it("해당 예외를 Result에서 throw한다.") {
shouldThrowWithMessage<IllegalArgumentException>("Throw error for test.") {
throwOnJoinWithContextOrchestrator.sagaSync(listOf())
.decodeResultOrThrow(object: TypeReference<List<Home>>(){})
.decodeResultOrThrow(object : TypeReference<List<Home>>() {})
}
}
}
Expand All @@ -281,7 +285,7 @@ internal class OrchestratorTest(
it("해당 예외를 Result에서 throw한다.") {
shouldThrowWithMessage<IllegalArgumentException>("Throw error for test.") {
throwOnCommitWithContextOrchestrator.sagaSync(listOf())
.decodeResultOrThrow(object: TypeReference<List<Home>>(){})
.decodeResultOrThrow(object : TypeReference<List<Home>>() {})
}
}
}
Expand All @@ -297,6 +301,17 @@ internal class OrchestratorTest(
}
}
}

describe("throwHttpClientErrorExceptionOnStartOrchestrator 구현채는") {
context("처리할 수 없는 HttpClientErrorException이 던져지면") {
it("ResultException을 Result에 담고 timeout시간안에 예외를 반환한다") {
shouldThrowExactly<ResultException> {
throwHttpClientErrorExceptionOnStartOrchestrator.sagaSync("")
.decodeResultOrThrow(String::class)
}
}
}
}
}) {
data class Home(
val address: String,
Expand Down
Loading