Skip to content

Commit

Permalink
fix: Infinite loading phenomenon when error encoding fails
Browse files Browse the repository at this point in the history
  • Loading branch information
devxb committed Dec 30, 2024
1 parent a113d7f commit 1f466f1
Show file tree
Hide file tree
Showing 6 changed files with 51 additions and 12 deletions.
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("ResultExceptionResult에 담고 timeout시간안에 예외를 반환한다") {
shouldThrowExactly<ResultException> {
throwHttpClientErrorExceptionOnStartOrchestrator.sagaSync("")
.decodeResultOrThrow(String::class)
}
}
}
}
}) {
data class Home(
val address: String,
Expand Down

0 comments on commit 1f466f1

Please sign in to comment.