no.ks.kes.test.example.Engine.kt Maven / Gradle / Ivy
The newest version!
package no.ks.kes.test.example
import no.ks.kes.lib.*
import no.ks.kes.serdes.jackson.JacksonCmdSerdes
import no.ks.kes.serdes.jackson.JacksonEventSerdes
import java.time.Duration
import java.time.Instant
import java.util.*
/**
* All example code are considered to be part of the documentation and may be changed at any time without past notice
*/
private val LOG = mu.KotlinLogging.logger { }
data class EngineProperties(val id: UUID, val running: Boolean, val startCount: Int = 0) : Aggregate
const val ENGINE_AGGREGATE_TYPE = "Engine"
const val SAGA_SERILIZATION_ID = "EngineSaga"
data class EngineSagaState(val aggregateId: UUID, val startInitiated: Boolean, val stoppedBySaga: Boolean = false)
object EngineSaga : Saga(EngineSagaState::class, SAGA_SERILIZATION_ID) {
init {
init { _: Events.Created, aggregateId: UUID ->
LOG.debug { "Saga created: $aggregateId" }
dispatch(Cmds.Start(aggregateId = aggregateId))
setState(EngineSagaState(aggregateId = aggregateId, startInitiated = true))
}
apply { _: Events.Stopped, aggregateId: UUID ->
LOG.debug { "Saga handles Stopped: $aggregateId" }
setState(state.copy(startInitiated = false))
}
timeout({ _: Events.Started, aggregateId: UUID -> aggregateId }, { Instant.now().plus(Duration.ofSeconds(5L)) }) {
LOG.debug { "Saga timed: ${state.aggregateId}" }
if (state.startInitiated) {
setState(state.copy(stoppedBySaga = true))
dispatch(Cmds.Stop(state.aggregateId))
}
}
}
}
object Engine : AggregateConfiguration(ENGINE_AGGREGATE_TYPE) {
init {
init { _: Events.Created, aggregateId: UUID ->
EngineProperties(id = aggregateId, running = false)
}
applyEvent { copy(running = true, startCount = startCount + 1) }
apply { copy(running = false) }
}
}
class EngineCmdHandler(repository: AggregateRepository) : CmdHandler(repository, Engine) {
init {
init {
LOG.debug { "Create command: ${it.aggregateId}" }
Result.Succeed(
Event( eventData = Events.Created(it.aggregateId), aggregateId = it.aggregateId))
}
apply {
LOG.debug { "Tries to start" }
if (running) {
Result.Succeed()
} else {
Result.Succeed(
Event( eventData = Events.Started(it.aggregateId), aggregateId = it.aggregateId)
)
}
}
apply {
if (running) {
Result.Succeed(
Event( eventData = Events.Stopped(it.aggregateId), aggregateId = it.aggregateId)
)
} else {
Result.Fail(RuntimeException("Can not stop engine that has already been stopped"))
}
}
apply {
Result.Succeed()
}
}
}
abstract class EngineCommand(override val aggregateId: UUID) : Cmd
object Cmds {
val all = setOf(Create::class, Start::class, Stop::class, Check::class)
val serdes = JacksonCmdSerdes(all)
@SerializationId("Created")
data class Create(override val aggregateId: UUID) : EngineCommand(aggregateId)
@SerializationId("Start")
data class Start(override val aggregateId: UUID) : EngineCommand(aggregateId)
@SerializationId("Stop")
data class Stop(override val aggregateId: UUID) : EngineCommand(aggregateId)
@SerializationId("Check")
data class Check(override val aggregateId: UUID) : EngineCommand(aggregateId)
}
abstract class EngineEvent(val description: String) : EventData {
val timestamp: Instant = Instant.now()
}
object Events {
val all = setOf(Created::class, Started::class, Stopped::class)
val serdes = JacksonEventSerdes(all)
@SerializationId("Created")
data class Created(val aggregateId: UUID) : EngineEvent("Created engine with id $aggregateId")
@SerializationId("Started")
data class Started(val aggregateId: UUID) : EngineEvent("Engine $aggregateId started")
@SerializationId("Stopped")
data class Stopped(val aggregateId: UUID) : EngineEvent("Engine $aggregateId stopped")
}
class EnginesProjection: Projection() {
private val enginesDefined = mutableSetOf()
private val runningEngines = mutableSetOf()
private val stoppedEngines = mutableSetOf()
val all: Set
get() = enginesDefined.toSet()
val allRunning: Set
get() = runningEngines.toSet()
val allStopped: Set
get() = stoppedEngines.toSet()
init {
on {
enginesDefined.plusAssign(it.aggregateId)
}
on {
runningEngines.plusAssign(it.aggregateId)
stoppedEngines.minusAssign(it.aggregateId)
}
on {
stoppedEngines.plusAssign(it.aggregateId)
runningEngines.minusAssign(it.aggregateId)
}
}
}