Search code examples
quarkusoptaplanner

Optaplanner: How to get solver instance in Quarkus


I am using Quarkus optaplanner, so instead of using SolverFactory to build a solver, I us ethe Quarkus way to inject a solverManager then let it solve the problem:

val solverJob: SolverJob<SolarDesign, UUID> = solverManager.solve(problemId, problem) 

But I want to still be able to addEventListener like:

solver.addEventListener(SolverEventListener<SolarDesign>() {
            fun bestSolutionChanged(event: BestSolutionChangedEvent<MyProblem>) {
                val solution = event.getNewBestSolution()
                if (solution.score.isFeasible()) {
                    println("found new best solution")
                    println(solution)
                }
            }
        })

Question is how do I get a solver instance in Quarkus optaplanner so I can use it to addEventListener? It does not seem to be doable from solverManager.

Thanks


Solution

  • The following example shows how to obtain a Solver instance in Quarkus. The SolverManager API does not cover this option so the alternative approach is to inject a SolverFactory, use it to build a Solver instance and manage its lifecycle yourself.

    The example also shows how to get access to the Phase lifecycle. It can be useful for experiments during development. However, that's only possible through casting the solver instance to DefaultSolver, which is an internal API. There are no backward compatibility guarantees on the internal classes. They can significantly change in future minor releases and cause compilation errors if you use them in your code. Do not use it in production.

    class MySolverResource(private val solverFactory: SolverFactory<SolarDesign>) {
    
      fun solve(problemId : UUID) {
        // WARNING: DefaultSolver is OptaPlanner's internal class.
        // Backward compatibility is not guaranteed.
        // Its usage is totally not recommended.
        val solver: DefaultSolver<SolarDesign> = solverFactory.buildSolver() as DefaultSolver<SolarDesign>
        solver.addPhaseLifecycleListener(object : PhaseLifecycleListenerAdapter<SolarDesign>() {
          override fun stepEnded(stepScope: AbstractStepScope<SolarDesign>) {
            printSolution(stepScope.createOrGetClonedSolution())
          }
        })
        solver.solve(loadProblem(problemId))
      }
    
      fun printSolution(solution: SolarDesign) {}
    }