Skip to content

Commit 1f466f1

Browse files
committed
fix: Infinite loading phenomenon when error encoding fails
1 parent a113d7f commit 1f466f1

File tree

6 files changed

+51
-12
lines changed

6 files changed

+51
-12
lines changed

gradle/test.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ dependencies {
1414
testImplementation "org.awaitility:awaitility:${awaitilityVersion}"
1515

1616
testImplementation "io.jsonwebtoken:jjwt-api:0.12.5"
17+
testImplementation "org.springframework.boot:spring-boot-starter-web"
1718
runtimeOnly "io.jsonwebtoken:jjwt-impl:0.12.5"
1819
runtimeOnly "io.jsonwebtoken:jjwt-jackson:0.12.5"
1920
}

src/main/kotlin/org/rooftop/netx/api/Exceptions.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package org.rooftop.netx.api
22

3+
import com.fasterxml.jackson.annotation.JsonIgnoreProperties
4+
35
class EncodeException(message: String, throwable: Throwable) : RuntimeException(message, throwable)
46

57
class DecodeException(message: String, throwable: Throwable) : RuntimeException(message, throwable)
@@ -16,4 +18,5 @@ class FailedAckSagaException(message: String) : RuntimeException(message)
1618
class ResultTimeoutException(message: String, throwable: Throwable) :
1719
RuntimeException(message, throwable)
1820

21+
@JsonIgnoreProperties(ignoreUnknown = true)
1922
class ResultException(message: String) : RuntimeException(message)

src/main/kotlin/org/rooftop/netx/redis/RedisResultHolder.kt

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,10 @@ package org.rooftop.netx.redis
22

33
import com.fasterxml.jackson.databind.ObjectMapper
44
import com.fasterxml.jackson.module.kotlin.jacksonTypeRef
5-
import org.rooftop.netx.core.Codec
65
import org.rooftop.netx.api.Result
6+
import org.rooftop.netx.api.ResultException
77
import org.rooftop.netx.api.ResultTimeoutException
8+
import org.rooftop.netx.core.Codec
89
import org.rooftop.netx.engine.ResultHolder
910
import org.rooftop.netx.engine.logging.info
1011
import org.springframework.data.redis.core.ReactiveRedisTemplate
@@ -73,10 +74,20 @@ internal class RedisResultHolder(
7374
}
7475

7576
override fun <T : Throwable> setFailResult(id: String, result: T): Mono<T> {
76-
val error = Error(
77-
objectMapper.writeValueAsString(result::class.java),
78-
objectMapper.writeValueAsString(result)
79-
)
77+
val error = runCatching {
78+
Error(
79+
type = objectMapper.writeValueAsString(result::class.java),
80+
error = objectMapper.writeValueAsString(result),
81+
)
82+
}.getOrElse {
83+
Error(
84+
type = objectMapper.writeValueAsString(ResultException::class.java),
85+
error = objectMapper.writeValueAsString(
86+
ResultException("Cannot encode fail result to json cause \"${it.message}\"")
87+
),
88+
)
89+
}
90+
8091
val encodedError = objectMapper.writeValueAsString(error)
8192
return reactiveRedisTemplate.opsForList()
8293
.leftPush(

src/main/kotlin/org/rooftop/netx/redis/RedisSagaConfigurer.kt

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,6 @@
11
package org.rooftop.netx.redis
22

3-
import com.fasterxml.jackson.annotation.JsonAutoDetect
4-
import com.fasterxml.jackson.annotation.JsonCreator
5-
import com.fasterxml.jackson.annotation.JsonIgnore
6-
import com.fasterxml.jackson.annotation.PropertyAccessor
3+
import com.fasterxml.jackson.annotation.*
74
import com.fasterxml.jackson.databind.DeserializationFeature
85
import com.fasterxml.jackson.databind.ObjectMapper
96
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule

src/test/kotlin/org/rooftop/netx/engine/OrchestratorConfigurer.kt

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ import org.rooftop.netx.engine.OrchestratorTest.Companion.rollbackOrchestratorRe
1010
import org.rooftop.netx.engine.OrchestratorTest.Companion.upChainResult
1111
import org.springframework.context.annotation.Bean
1212
import org.springframework.context.annotation.Configuration
13+
import org.springframework.http.HttpStatus
14+
import org.springframework.web.client.HttpClientErrorException
1315
import reactor.core.publisher.Mono
1416
import java.time.Instant
1517

@@ -317,6 +319,16 @@ internal class OrchestratorConfigurer(
317319
.commit { "" }
318320
}
319321

322+
@Bean(name = ["throwHttpClientErrorExceptionOnStartOrchestrator"])
323+
fun throwHttpClientErrorExceptionOnStartOrchestrator(): Orchestrator<String, String> {
324+
return OrchestratorFactory.instance()
325+
.create<String>("throwHttpClientErrorExceptionOnStartOrchestrator")
326+
.startWithContext({ _, _ ->
327+
throw HttpClientErrorException(HttpStatus.UNAUTHORIZED)
328+
})
329+
.commitWithContext({ _, _ -> "" })
330+
}
331+
320332
fun interface ListOrchestrate :
321333
ContextOrchestrate<List<OrchestratorTest.Home>, List<OrchestratorTest.Home>> {
322334

src/test/kotlin/org/rooftop/netx/engine/OrchestratorTest.kt

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,21 @@ package org.rooftop.netx.engine
22

33
import io.jsonwebtoken.JwtException
44
import io.kotest.assertions.nondeterministic.eventually
5+
import io.kotest.assertions.throwables.shouldThrowExactly
56
import io.kotest.assertions.throwables.shouldThrowWithMessage
67
import io.kotest.core.annotation.DisplayName
78
import io.kotest.core.spec.style.DescribeSpec
89
import io.kotest.matchers.equality.shouldBeEqualToComparingFields
910
import io.kotest.matchers.equals.shouldBeEqual
1011
import org.rooftop.netx.api.Orchestrator
12+
import org.rooftop.netx.api.ResultException
1113
import org.rooftop.netx.api.TypeReference
1214
import org.rooftop.netx.meta.EnableSaga
1315
import org.rooftop.netx.redis.RedisContainer
1416
import org.springframework.beans.factory.annotation.Qualifier
1517
import org.springframework.test.context.ContextConfiguration
1618
import org.springframework.test.context.TestPropertySource
19+
import org.springframework.web.client.HttpClientErrorException
1720
import java.time.Instant
1821
import kotlin.time.Duration.Companion.seconds
1922

@@ -45,6 +48,7 @@ internal class OrchestratorTest(
4548
@Qualifier("throwOnJoinWithContextOrchestrator") private val throwOnJoinWithContextOrchestrator: Orchestrator<List<Home>, List<Home>>,
4649
@Qualifier("throwOnCommitWithContextOrchestrator") private val throwOnCommitWithContextOrchestrator: Orchestrator<List<Home>, List<Home>>,
4750
@Qualifier("throwJwtExceptionOnStartOrchestrator") private val throwJwtExceptionOnStartOrchestrator: Orchestrator<String, String>,
51+
@Qualifier("throwHttpClientErrorExceptionOnStartOrchestrator") private val throwHttpClientErrorExceptionOnStartOrchestrator: Orchestrator<String, String>,
4852
) : DescribeSpec({
4953

5054
describe("numberOrchestrator 구현채는") {
@@ -259,7 +263,7 @@ internal class OrchestratorTest(
259263
it("해당 예외를 Result에서 throw한다.") {
260264
shouldThrowWithMessage<IllegalArgumentException>("Throw error for test.") {
261265
throwOnStartWithContextOrchestrator.sagaSync(listOf())
262-
.decodeResultOrThrow(object: TypeReference<List<Home>>(){})
266+
.decodeResultOrThrow(object : TypeReference<List<Home>>() {})
263267
}
264268
}
265269
}
@@ -270,7 +274,7 @@ internal class OrchestratorTest(
270274
it("해당 예외를 Result에서 throw한다.") {
271275
shouldThrowWithMessage<IllegalArgumentException>("Throw error for test.") {
272276
throwOnJoinWithContextOrchestrator.sagaSync(listOf())
273-
.decodeResultOrThrow(object: TypeReference<List<Home>>(){})
277+
.decodeResultOrThrow(object : TypeReference<List<Home>>() {})
274278
}
275279
}
276280
}
@@ -281,7 +285,7 @@ internal class OrchestratorTest(
281285
it("해당 예외를 Result에서 throw한다.") {
282286
shouldThrowWithMessage<IllegalArgumentException>("Throw error for test.") {
283287
throwOnCommitWithContextOrchestrator.sagaSync(listOf())
284-
.decodeResultOrThrow(object: TypeReference<List<Home>>(){})
288+
.decodeResultOrThrow(object : TypeReference<List<Home>>() {})
285289
}
286290
}
287291
}
@@ -297,6 +301,17 @@ internal class OrchestratorTest(
297301
}
298302
}
299303
}
304+
305+
describe("throwHttpClientErrorExceptionOnStartOrchestrator 구현채는") {
306+
context("처리할 수 없는 HttpClientErrorException이 던져지면") {
307+
it("ResultExceptionResult에 담고 timeout시간안에 예외를 반환한다") {
308+
shouldThrowExactly<ResultException> {
309+
throwHttpClientErrorExceptionOnStartOrchestrator.sagaSync("")
310+
.decodeResultOrThrow(String::class)
311+
}
312+
}
313+
}
314+
}
300315
}) {
301316
data class Home(
302317
val address: String,

0 commit comments

Comments
 (0)