-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
refactor: Improve Orchestrator API (#91)
* feat: Support TypeReference on Codec * refactor: Type inferencible in OrchestratorChain * feat: Rollback chaining * test: Orchestrator Load Test * fix: Rollback event가 NUll일때, 예외를 던지지않도록 수정한다 * test: Next orchestrator supports java * docs: version up 0.3.1 to 0.3.2 * refactor: Undostate를 찾을 수 없으면, 트랜잭션에 참여하지 않은것으로 간주한다 * refactor: remove unused import * refactor: Make param collections immutable.
- Loading branch information
Showing
44 changed files
with
1,390 additions
and
1,385 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,6 @@ | ||
package org.rooftop.netx.api | ||
|
||
fun interface OrchestrateFunction<T> { | ||
fun interface OrchestrateFunction<T : Any, V : Any> { | ||
|
||
fun orchestrate(orchestrateRequest: OrchestrateRequest): T | ||
fun orchestrate(request: T): V | ||
} |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
package org.rooftop.netx.api | ||
|
||
import kotlin.reflect.KClass | ||
|
||
class Result<T : Any> private constructor( | ||
val isSuccess: Boolean, | ||
private val codec: Codec, | ||
private val result: String?, | ||
private val error: Error? = null, | ||
) { | ||
|
||
fun decodeResult(type: Class<T>): T = decodeResult(type.kotlin) | ||
|
||
fun decodeResult(type: KClass<T>): T = result?.let { | ||
codec.decode(it, type) | ||
} ?: throw ResultException("Cannot decode result cause Result is fail state") | ||
|
||
fun throwError() = error?.throwError(codec) | ||
?: throw ResultException("Cannot throw error cause Result is success state") | ||
|
||
override fun toString(): String { | ||
return "Result(isSuccess=$isSuccess, codec=$codec, result=$result, error=$error)" | ||
} | ||
|
||
private class Error( | ||
private val error: String, | ||
private val type: KClass<Throwable> | ||
) { | ||
|
||
fun throwError(codec: Codec) { | ||
throw codec.decode(error, type) | ||
} | ||
|
||
override fun toString(): String { | ||
return "Error(error='$error', type=$type)" | ||
} | ||
} | ||
|
||
internal companion object { | ||
|
||
fun <T : Any> success( | ||
codec: Codec, | ||
result: String, | ||
): Result<T> { | ||
return Result( | ||
true, | ||
codec, | ||
result, | ||
null, | ||
) | ||
} | ||
|
||
fun <T : Any> fail( | ||
codec: Codec, | ||
error: String, | ||
type: KClass<Throwable>, | ||
): Result<T> { | ||
return Result( | ||
false, | ||
codec, | ||
null, | ||
Error(error, type), | ||
) | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
package org.rooftop.netx.api | ||
|
||
fun interface RollbackFunction<T : Any, V : Any?> { | ||
|
||
fun rollback(request: T): V | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
117 changes: 117 additions & 0 deletions
117
src/main/kotlin/org/rooftop/netx/engine/AbstractOrchestrateListener.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
package org.rooftop.netx.engine | ||
|
||
import org.rooftop.netx.api.Codec | ||
import org.rooftop.netx.api.TransactionEvent | ||
import org.rooftop.netx.api.TransactionManager | ||
import reactor.core.publisher.Mono | ||
import reactor.core.scheduler.Schedulers | ||
import kotlin.reflect.KClass | ||
|
||
internal abstract class AbstractOrchestrateListener<T : Any, V : Any> internal constructor( | ||
private val orchestratorId: String, | ||
val orchestrateSequence: Int, | ||
private val codec: Codec, | ||
private val transactionManager: TransactionManager, | ||
private val requestHolder: RequestHolder, | ||
private val resultHolder: ResultHolder, | ||
) { | ||
|
||
var isFirst: Boolean = true | ||
var isLast: Boolean = true | ||
var isRollbackable: Boolean = false | ||
var beforeRollbackOrchestrateSequence: Int = 0 | ||
|
||
private var nextOrchestrateListener: AbstractOrchestrateListener<V, Any>? = null | ||
private var nextRollbackOrchestrateListener: AbstractOrchestrateListener<V, Any>? = null | ||
private var castableType: KClass<out T>? = null | ||
|
||
@Suppress("UNCHECKED_CAST") | ||
internal fun setNextOrchestrateListener(nextOrchestrateListener: AbstractOrchestrateListener<out Any, out Any>) { | ||
this.nextOrchestrateListener = | ||
nextOrchestrateListener as AbstractOrchestrateListener<V, Any> | ||
} | ||
|
||
@Suppress("UNCHECKED_CAST") | ||
internal fun setNextRollbackOrchestrateListener(nextRollbackOrchestrateListener: AbstractOrchestrateListener<out Any, out Any>) { | ||
this.nextRollbackOrchestrateListener = | ||
nextRollbackOrchestrateListener as AbstractOrchestrateListener<V, Any> | ||
} | ||
|
||
internal fun setCastableType(type: KClass<out T>) { | ||
castableType = type | ||
} | ||
|
||
internal fun Mono<V>.setNextCastableType(): Mono<V> { | ||
return this.doOnNext { | ||
nextOrchestrateListener?.castableType = it::class | ||
nextRollbackOrchestrateListener?.castableType = it::class | ||
} | ||
} | ||
|
||
protected fun Mono<*>.getHeldRequest(transactionEvent: TransactionEvent): Mono<T> { | ||
return this.flatMap { | ||
requestHolder.getRequest( | ||
"${transactionEvent.transactionId}:$orchestrateSequence", | ||
getCastableType() | ||
) | ||
} | ||
} | ||
|
||
protected fun Mono<T>.holdRequestIfRollbackable(transactionEvent: TransactionEvent): Mono<T> { | ||
return this.flatMap { request -> | ||
if (!isRollbackable) { | ||
Mono.just(request) | ||
} | ||
requestHolder.setRequest( | ||
"${transactionEvent.transactionId}:$orchestrateSequence", | ||
request | ||
) | ||
} | ||
} | ||
|
||
protected fun getCastableType(): KClass<out T> { | ||
return castableType | ||
?: throw NullPointerException("OrchestratorId \"$orchestratorId\", OrchestrateSequence \"$orchestrateSequence\"'s CastableType was null") | ||
} | ||
|
||
protected fun cast(data: String): T { | ||
return castableType?.let { | ||
codec.decode(data, it) | ||
} ?: throw NullPointerException("Cannot cast \"$data\" cause, castableType is null") | ||
} | ||
|
||
protected fun TransactionEvent.toOrchestrateEvent(): Mono<OrchestrateEvent> = | ||
Mono.just(this.decodeEvent(OrchestrateEvent::class)) | ||
|
||
protected fun <S> Mono<S>.onErrorRollback( | ||
transactionId: String, | ||
orchestrateEvent: OrchestrateEvent, | ||
): Mono<S> = this.onErrorResume { | ||
holdFailResult(transactionId, it) | ||
rollback(transactionId, it, orchestrateEvent) | ||
Mono.empty() | ||
} | ||
|
||
private fun holdFailResult(transactionId: String, throwable: Throwable) { | ||
resultHolder.setFailResult(transactionId, throwable) | ||
.subscribeOn(Schedulers.parallel()).subscribe() | ||
} | ||
|
||
private fun rollback( | ||
transactionId: String, | ||
throwable: Throwable, | ||
orchestrateEvent: OrchestrateEvent, | ||
) { | ||
transactionManager.rollback( | ||
transactionId = transactionId, | ||
cause = throwable.message ?: throwable.localizedMessage, | ||
event = orchestrateEvent | ||
).subscribeOn(Schedulers.parallel()).subscribe() | ||
} | ||
|
||
override fun toString(): String { | ||
return "AbstractOrchestrateListener(orchestratorId='$orchestratorId', orchestrateSequence=$orchestrateSequence, codec=$codec, transactionManager=$transactionManager, requestHolder=$requestHolder, isFirst=$isFirst, isLast=$isLast, isRollbackable=$isRollbackable, beforeRollbackOrchestrateSequence=$beforeRollbackOrchestrateSequence, nextOrchestrateListener=$nextOrchestrateListener, nextRollbackOrchestrateListener=$nextRollbackOrchestrateListener, castableType=$castableType)" | ||
} | ||
|
||
|
||
} |
Oops, something went wrong.