The following is my gradle kotlin spring-boot project’s configuration and saga:
person service application.properties:
spring.datasource.url=jdbc:postgresql://${DB_HOST:localhost}:${DB_PORT:5432}/demodb
spring.datasource.username=${DB_USER:postgres}
spring.datasource.password=${DB_PASSWORD:postgres}
spring.jpa.database-platform=org.hibernate.dialect.PostgreSQLDialect
spring.jpa.hibernate.ddl-auto=update
server.port=${PORT:8081}
store service application.properties:
spring.datasource.url=jdbc:postgresql://${DB_HOST:localhost}:${DB_PORT:5432}/demodb
spring.datasource.username=${DB_USER:postgres}
spring.datasource.password=${DB_PASSWORD:postgres}
spring.jpa.database-platform=org.hibernate.dialect.PostgreSQLDialect
spring.jpa.hibernate.ddl-auto=update
server.port=${PORT:8082}
using dependencies:
org.axonframework:axon-bom version 4.6.0
org.springframework.boot version 2.7.5
kotlin version 1.6.21
postgres
Using a saga:
package com.example.person
import com.example.common.PersonEvents
import com.example.common.StoreCommands as storeCommands
import com.example.common.StoreEvents as storeEvents
import com.example.common.PersonCommands as personCommands
import org.axonframework.commandhandling.gateway.CommandGateway
import org.axonframework.modelling.saga.EndSaga
import org.axonframework.modelling.saga.SagaEventHandler
import org.axonframework.modelling.saga.StartSaga
import org.axonframework.spring.stereotype.Saga
import org.springframework.beans.factory.annotation.Autowired
@Saga
class PersonShoppingSaga {
@Transient
@Autowired
lateinit var commandGateway: CommandGateway
lateinit var name: String
var listNumber: Int = 0
lateinit var shoppingList: List<String>
var shopping: Boolean = false
@StartSaga
@SagaEventHandler(associationProperty = "name")
fun handle(event: PersonEvents.shoppingListRecieved){
if (shopping) {
TODO() // person is already shopping, ask processor to wait longer.
}
shopping = true
shoppingList = event.list
name = event.name
walkToStore()
}
@SagaEventHandler(associationProperty = "person", keyName = "name")
fun handle(event: storeEvents.travelledToStore){
listNumber ++
walkToStore()
}
fun walkToStore(){
if (listNumber == shoppingList.size -1) {
commandGateway.sendAndWait<personCommands>(personCommands.finishedShopping(name, shoppingList))
}
commandGateway.sendAndWait<storeCommands>(storeCommands.travelToStore(shoppingList.get(listNumber), name))
}
@EndSaga
@SagaEventHandler(associationProperty = "name")
fun handle(event: PersonEvents.shoppingListCompleted){
println("completed shopping list")
}
}
When there is a random amount of chances for failure in the “travelToStore” command, when I run the example project, and restart the service, the saga does not retry consuming the event that caused an exception and continues consuming new events.
Is there some configuration that I can set to make the saga not continue with the next event untill the events were processed successfully?