Skip to content

Commit 31b0393

Browse files
authored
refactor: orchestrator's rollback start previous sequence (#138)
* test: Orchestrator Result test 를 추가한다 * refactor: Orchestrator도중에 예외가 발생하면, 이전 chain부터 rollback이 수행되도록 한다 * docs: Readme.md에 rollback 발생 순서를 수정한다 * build: version을 0.4.2에서 0.4.3으로 올린다
1 parent 5fd082f commit 31b0393

File tree

9 files changed

+74
-52
lines changed

9 files changed

+74
-52
lines changed

README.md

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
55
<br>
66

7-
![version 0.4.2](https://img.shields.io/badge/version-0.4.2-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)
7+
![version 0.4.3](https://img.shields.io/badge/version-0.4.3-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)
88
![redis--stream](https://img.shields.io/badge/-redis--stream-da2020?style=flat-square&logo=Redis&logoColor=white)
99

1010
**TPS(6,000)** on my Macbook air m2(default options). _[link](#Test1-TPS)_
@@ -120,12 +120,8 @@ class OrchestratorConfigurer(
120120
)
121121
.commit(
122122
orchestrate = { request ->
123-
// When an error occurs, all rollbacks are called from the bottom up,
124-
// starting from the location where the error occurred.
123+
// If a rollback occurs here, all the above rollback functions will be executed sequentially.
125124
throw IllegalArgumentException("Oops! Something went wrong..")
126-
},
127-
rollback = { request ->
128-
// ...
129125
}
130126
)
131127
}

gradle.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ kotlin.code.style=official
22

33
### Project ###
44
group=org.rooftopmsa
5-
version=0.4.2
5+
version=0.4.3
66
compatibility=17
77

88
### Sonarcloud ###

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

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -63,43 +63,35 @@ interface OrchestrateChain<OriginReq : Any, T : Any, V : Any> {
6363
* Commits the saga with the operation.
6464
*
6565
* @param orchestrate Operation to be executed along with the commit.
66-
* @param rollback Rollback function to be executed if an exception is thrown in the current orchestrate.
6766
* @param S The final return value of Orchestrator.
6867
* @return Orchestrator
6968
* @see Orchestrate
70-
* @see Rollback*
7169
*/
7270
fun <S : Any> commit(
7371
orchestrate: Orchestrate<V, S>,
74-
rollback: Rollback<V, *>? = null,
7572
): Orchestrator<OriginReq, S>
7673

7774
/**
7875
* @see commit
7976
*/
8077
fun <S : Any> commitReactive(
8178
orchestrate: Orchestrate<V, Mono<S>>,
82-
rollback: Rollback<V, Mono<*>>? = null,
8379
): Orchestrator<OriginReq, S>
8480

8581
/**
8682
* @param contextOrchestrate Allows using Context maintained in each Saga.
87-
* @param contextRollback Allows using Context maintained in each Saga.
8883
* @see commit
8984
* @see contextOrchestrate
90-
* @see contextRollback
9185
*/
9286
fun <S : Any> commitWithContext(
9387
contextOrchestrate: ContextOrchestrate<V, S>,
94-
contextRollback: ContextRollback<V, *>? = null,
9588
): Orchestrator<OriginReq, S>
9689

9790
/**
9891
* @see commitWithContext
9992
*/
10093
fun <S : Any> commitReactiveWithContext(
10194
contextOrchestrate: ContextOrchestrate<V, Mono<S>>,
102-
contextRollback: ContextRollback<V, Mono<*>>? = null,
10395
): Orchestrator<OriginReq, S>
10496

10597
interface Pre<T : Any> {

src/main/kotlin/org/rooftop/netx/engine/DefaultOrchestrateChain.kt

Lines changed: 10 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -146,26 +146,20 @@ internal class DefaultOrchestrateChain<OriginReq : Any, T : Any, V : Any> privat
146146

147147
override fun <S : Any> commit(
148148
orchestrate: Orchestrate<V, S>,
149-
rollback: Rollback<V, *>?,
150149
): Orchestrator<OriginReq, S> {
151150
val nextCommitOrchestrateListener =
152151
getCommitOrchestrateListener<V, S>(CommandType.DEFAULT, orchestrate)
153-
val nextRollbackOrchestrateListener =
154-
getRollbackOrchestrateListener<V, S>(CommandType.DEFAULT, rollback)
155152

156-
return createOrchestrator(nextCommitOrchestrateListener, nextRollbackOrchestrateListener)
153+
return createOrchestrator(nextCommitOrchestrateListener)
157154
}
158155

159156
override fun <S : Any> commitWithContext(
160157
contextOrchestrate: ContextOrchestrate<V, S>,
161-
contextRollback: ContextRollback<V, *>?
162158
): Orchestrator<OriginReq, S> {
163159
val nextCommitOrchestrateListener =
164160
getCommitOrchestrateListener<V, S>(CommandType.CONTEXT, contextOrchestrate)
165-
val nextRollbackOrchestrateListener =
166-
getRollbackOrchestrateListener<V, S>(CommandType.CONTEXT, contextRollback)
167161

168-
return createOrchestrator(nextCommitOrchestrateListener, nextRollbackOrchestrateListener)
162+
return createOrchestrator(nextCommitOrchestrateListener)
169163
}
170164

171165
private fun <T : Any, V : Any> getCommitOrchestrateListener(
@@ -200,15 +194,14 @@ internal class DefaultOrchestrateChain<OriginReq : Any, T : Any, V : Any> privat
200194

201195
private fun <S : Any> createOrchestrator(
202196
nextCommitOrchestrateListener: CommitOrchestrateListener<V, S>,
203-
nextRollbackOrchestrateListener: RollbackOrchestrateListener<V, S>?
204197
): Orchestrator<OriginReq, S> {
205198
return chainContainer.orchestratorCache.cache(orchestratorId) {
206199
val nextDefaultOrchestrateChain = DefaultOrchestrateChain(
207200
orchestratorId,
208201
orchestrateSequence + 1,
209202
chainContainer,
210203
nextCommitOrchestrateListener,
211-
nextRollbackOrchestrateListener,
204+
null,
212205
this,
213206
)
214207
this.nextDefaultOrchestrateChain = nextDefaultOrchestrateChain
@@ -227,39 +220,32 @@ internal class DefaultOrchestrateChain<OriginReq : Any, T : Any, V : Any> privat
227220

228221
override fun <S : Any> commitReactive(
229222
orchestrate: Orchestrate<V, Mono<S>>,
230-
rollback: Rollback<V, Mono<*>>?,
231223
): Orchestrator<OriginReq, S> {
232224
val nextJoinOrchestrateListener =
233225
getMonoCommitOrchestrateListener<V, S>(CommandType.DEFAULT, orchestrate)
234-
val nextRollbackOrchestrateListener =
235-
getMonoRollbackOrchestrateListener<V, S>(CommandType.DEFAULT, rollback)
236226

237-
return createOrchestrator(nextJoinOrchestrateListener, nextRollbackOrchestrateListener)
227+
return createOrchestrator(nextJoinOrchestrateListener)
238228
}
239229

240230
override fun <S : Any> commitReactiveWithContext(
241231
contextOrchestrate: ContextOrchestrate<V, Mono<S>>,
242-
contextRollback: ContextRollback<V, Mono<*>>?
243232
): Orchestrator<OriginReq, S> {
244233
val nextJoinOrchestrateListener =
245234
getMonoCommitOrchestrateListener<V, S>(CommandType.CONTEXT, contextOrchestrate)
246-
val nextRollbackOrchestrateListener =
247-
getMonoRollbackOrchestrateListener<V, S>(CommandType.CONTEXT, contextRollback)
248235

249-
return createOrchestrator(nextJoinOrchestrateListener, nextRollbackOrchestrateListener)
236+
return createOrchestrator(nextJoinOrchestrateListener)
250237
}
251238

252239
private fun <S : Any> createOrchestrator(
253240
nextJoinOrchestrateListener: MonoCommitOrchestrateListener<V, S>,
254-
nextRollbackOrchestrateListener: MonoRollbackOrchestrateListener<V, S>?
255241
): Orchestrator<OriginReq, S> {
256242
return chainContainer.orchestratorCache.cache(orchestratorId) {
257243
val nextDefaultOrchestrateChain = DefaultOrchestrateChain(
258244
orchestratorId,
259245
orchestrateSequence + 1,
260246
chainContainer,
261247
nextJoinOrchestrateListener,
262-
nextRollbackOrchestrateListener,
248+
null,
263249
this,
264250
)
265251
this.nextDefaultOrchestrateChain = nextDefaultOrchestrateChain
@@ -330,6 +316,7 @@ internal class DefaultOrchestrateChain<OriginReq : Any, T : Any, V : Any> privat
330316

331317
private fun chainOrchestrateListeners(orchestrateListeners: List<Pair<AbstractOrchestrateListener<out Any, out Any>, AbstractOrchestrateListener<out Any, out Any>?>>) {
332318
var rollbackSequence = 0
319+
var beforeRollbackSequence = -1
333320
for (listenerWithIdx in orchestrateListeners.withIndex()) {
334321
val isFirst = listenerWithIdx.index == 0
335322
val isLast =
@@ -341,6 +328,9 @@ internal class DefaultOrchestrateChain<OriginReq : Any, T : Any, V : Any> privat
341328
rollbackSequence = it.orchestrateSequence
342329
}
343330
listener.rollbackSequence = rollbackSequence
331+
listener.beforeRollbackOrchestrateSequence = beforeRollbackSequence
332+
333+
beforeRollbackSequence = rollbackSequence
344334

345335
listener.isFirst = isFirst
346336
listener.isLast = isLast

src/main/kotlin/org/rooftop/netx/engine/listen/AbstractOrchestrateListener.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@ internal abstract class AbstractOrchestrateListener<T : Any, V : Any> internal c
153153
val rollbackOrchestrateEvent =
154154
OrchestrateEvent(
155155
orchestrateEvent.orchestratorId,
156-
rollbackSequence,
156+
beforeRollbackOrchestrateSequence,
157157
"",
158158
orchestrateEvent.context,
159159
)

src/test/java/org/rooftop/netx/javasupports/OrchestratorConfigurer.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,7 @@ public Orchestrator<Integer, Integer> intOrchestrator() {
2020
request -> request - 1
2121
)
2222
.commit(
23-
request -> request + 1,
24-
request -> request - 1
23+
request -> request + 1
2524
);
2625
}
2726
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ internal class OrchestratorConfigurer {
1717
Mono.fromCallable {
1818
request + 1
1919
}
20-
}, contextRollback = { _, request -> Mono.fromCallable { request - 1 } })
20+
})
2121
}
2222

2323
object IntOrchestrator : Orchestrate<Int, Int> {

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

Lines changed: 30 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -91,9 +91,6 @@ internal class OrchestratorConfigurer(
9191
rollbackOrchestratorResult.add("4")
9292
throw IllegalArgumentException("Rollback")
9393
},
94-
rollback = {
95-
rollbackOrchestratorResult.add("-4")
96-
}
9794
)
9895
}
9996

@@ -141,10 +138,9 @@ internal class OrchestratorConfigurer(
141138
val start1 = context.decodeContext("start-1", String::class)
142139
val join2 = context.decodeContext("join-2", String::class)
143140
val join3 = context.decodeContext("join-3", String::class)
144-
val rCommit4 = context.decodeContext("r-commit-4", String::class)
145141
val rJoin3 = context.decodeContext("r-join-3", String::class)
146142

147-
contextResult.addAll(listOf(start1, join2, join3, rCommit4, rJoin3))
143+
contextResult.addAll(listOf(start1, join2, join3, rJoin3))
148144
}
149145
)
150146
.joinWithContext(
@@ -171,9 +167,6 @@ internal class OrchestratorConfigurer(
171167
context.set("commit-4", request)
172168
throw IllegalArgumentException("Rollback")
173169
},
174-
contextRollback = { context, request ->
175-
context.set("r-commit-4", "r$request")
176-
}
177170
)
178171
}
179172

@@ -237,6 +230,35 @@ internal class OrchestratorConfigurer(
237230
.commit({ it })
238231
}
239232

233+
@Bean(name = ["throwOnStartOrchestrator"])
234+
fun throwOnStartOrchestrator(): Orchestrator<String, String> {
235+
return OrchestratorFactory.instance()
236+
.create<String>("throwOnStartOrchestrator")
237+
.start(
238+
orchestrate = {
239+
throw IllegalArgumentException("Throw error for test.")
240+
}
241+
)
242+
.commit({
243+
"Never reach this line."
244+
})
245+
}
246+
247+
@Bean(name = ["throwOnJoinOrchestrator"])
248+
fun throwOnJoinOrchestrator(): Orchestrator<String, String> {
249+
return OrchestratorFactory.instance()
250+
.create<String>("throwOnJoinOrchestrator")
251+
.start({
252+
"start success"
253+
})
254+
.join({
255+
throw IllegalArgumentException("Throw error for test.")
256+
})
257+
.commit({
258+
"Never reach this line."
259+
})
260+
}
261+
240262
object PairOrchestrate :
241263
Orchestrate<Pair<OrchestratorTest.Foo, OrchestratorTest.Foo>, Pair<OrchestratorTest.Foo, OrchestratorTest.Foo>> {
242264
override fun orchestrate(request: Pair<OrchestratorTest.Foo, OrchestratorTest.Foo>): Pair<OrchestratorTest.Foo, OrchestratorTest.Foo> {

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

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import io.kotest.core.annotation.DisplayName
66
import io.kotest.core.spec.style.DescribeSpec
77
import io.kotest.matchers.equality.shouldBeEqualToComparingFields
88
import io.kotest.matchers.equals.shouldBeEqual
9-
import io.kotest.matchers.shouldBe
109
import org.rooftop.netx.api.Orchestrator
1110
import org.rooftop.netx.api.TypeReference
1211
import org.rooftop.netx.meta.EnableSaga
@@ -39,6 +38,8 @@ internal class OrchestratorTest(
3938
@Qualifier("startWithContextOrchestrator") private val startWithContextOrchestrator: Orchestrator<String, String>,
4039
@Qualifier("fooContextOrchestrator") private val fooContextOrchestrator: Orchestrator<String, List<Foo>>,
4140
private val privateOrchestrator: Orchestrator<Private, Private>,
41+
@Qualifier("throwOnStartOrchestrator") private val throwOnStartOrchestrator: Orchestrator<String, String>,
42+
@Qualifier("throwOnJoinOrchestrator") private val throwOnJoinOrchestrator: Orchestrator<String, String>,
4243
) : DescribeSpec({
4344

4445
describe("numberOrchestrator 구현채는") {
@@ -97,10 +98,10 @@ internal class OrchestratorTest(
9798
}
9899

99100
describe("rollbackOrchestrator 구현채는") {
100-
val expected = listOf("1", "2", "3", "4", "-4", "-3", "-1")
101+
val expected = listOf("1", "2", "3", "4", "-3", "-1")
101102

102103
context("saga 메소드가 호출되면,") {
103-
it("실패한 부분부터 위로 거슬러 올라가며 롤백한다") {
104+
it("실패한 부분 위부터 위로 거슬러 올라가며 롤백한다") {
104105
val result = rollbackOrchestrator.sagaSync("")
105106

106107
result.isSuccess shouldBeEqual false
@@ -134,7 +135,7 @@ internal class OrchestratorTest(
134135
context("saga 메소드가 호출되면,") {
135136
val expected = listOf("1", "2", "3", "4", "-3", "-1")
136137

137-
it("실패한 부분부터 위로 거슬러 올라가며 롤백한다.") {
138+
it("실패한 부분위부터 위로 거슬러 올라가며 롤백한다.") {
138139
val result = monoRollbackOrchestrator.sagaSync("")
139140

140141
result.isSuccess shouldBeEqual false
@@ -150,7 +151,7 @@ internal class OrchestratorTest(
150151

151152
describe("contextOrchestrator 구현채는") {
152153
context("saga 메소드가 호출되면,") {
153-
val expected = listOf("0", "1", "2", "r3", "r2")
154+
val expected = listOf("0", "1", "2", "r2")
154155

155156
it("context 에서 아이템을 교환하며 Saga를 진행한다.") {
156157
val result = contextOrchestrator.sagaSync("0")
@@ -225,6 +226,28 @@ internal class OrchestratorTest(
225226
}
226227
}
227228
}
229+
230+
describe("throwOnStartOrchestrator 구현채는") {
231+
context("start에서 예외가 던져지면,") {
232+
it("해당 예외를 Result에서 throw한다.") {
233+
shouldThrowWithMessage<IllegalArgumentException>("Throw error for test.") {
234+
throwOnStartOrchestrator.sagaSync("throw error in start.")
235+
.decodeResultOrThrow(String::class)
236+
}
237+
}
238+
}
239+
}
240+
241+
describe("throwOnJoinOrchestrator 구현채는") {
242+
context("join에서 예외가 던져지면,") {
243+
it("해당 예외를 Result에서 throw한다.") {
244+
shouldThrowWithMessage<IllegalArgumentException>("Throw error for test.") {
245+
throwOnJoinOrchestrator.sagaSync("throw error in join.")
246+
.decodeResultOrThrow(String::class)
247+
}
248+
}
249+
}
250+
}
228251
}) {
229252
data class Home(
230253
val address: String,

0 commit comments

Comments
 (0)