class SolverManager implements SolverEventListener<VehicleRoutingSolution> {

    void startSolver(VehicleRoutingSolution solution) {
        if (solverFuture != null) {
            throw new IllegalStateException("Solver start has already been requested");
        }
        solverFuture = executor.submitListenable((SolvingTask) () -> solver.solve(solution));
        solverFuture.addCallback(
                // IMPORTANT: This is happening on the solver thread.
                // TODO in both cases restart or somehow recover?
                result -> {
                    if (!solver.isTerminateEarly()) {
                        // This is impossible. Solver in daemon mode can't return from solve() unless it has been
                        // terminated (see #stopSolver()) or throws an exception.
                        logger.error("Solver stopped solving but that shouldn't happen in daemon mode.");
                        eventPublisher.publishEvent(new ErrorEvent(this, "Solver stopped solving unexpectedly."));
                    }
                },
                exception -> {
                    logger.error("Solver failed", exception);
                    eventPublisher.publishEvent(new ErrorEvent(this, exception.toString()));
                });
    }

    @Autowired  SolverManager(
            Solver<VehicleRoutingSolution> solver,
            AsyncListenableTaskExecutor executor,
            RouteChangedEventPublisher routeChangedEventPublisher,
            ApplicationEventPublisher eventPublisher);

}