Replies: 3 comments 2 replies
-
Hello @tscript3r, and thanks for reaching out! |
Beta Was this translation helpful? Give feedback.
-
Hello, Thanks for your insights! My main need was simply to inject a custom ExecutorService into DefaultSolverManager. Since this is just a pet project, I’ve worked around it using reflection, but I imagine others might eventually need similar flexibility. In my case, I’m injecting a ThreadPoolExecutor with an ArrayBlockingQueue, wrapped in a proxy that extends ArrayBlockingQueue with the observer pattern functionality. This allows me to track queue positions of incoming solver requests and display real-time queue status to users. While a separate queue could be an alternative, this approach makes sense for my specific use case—plus, it was a fun challenge :) Also by having a reference to the ExecutorService, I can queue other resource-intensive jobs into the same executor, which is beneficial since I need to limit execution to a single heavy-duty thread due to constrained server resources. From what I see in the implementation, the main drawback of allowing an injected ExecutorService via the constructor is the potential for thread configuration inconsistencies. That said, adding more configurability in the future could be beneficial. Best regards, |
Beta Was this translation helpful? Give feedback.
-
Thank you for the explanation, @tscript3r! To your queue status problem, I think The other use - using the solver's executor for other tasks - is clearly not something we want to support. This mixes concerns; arguably, the solver should do its own thing, and whatever other tasks you have running, they should be isolated from that. Modern software architectures allow for that full well by allowing you to virtualize workloads. In general, I want to strongly discourage you from doing what you described here. The code is not designed to work like this, and by breaking apart the solver's internals, you expose yourself to changes in solver implementation, and all sorts of mysterious bugs. |
Beta Was this translation helpful? Give feedback.
-
Hi,
I'm using this library for my pet project and need more control over the solver thread pool. Specifically, I'd like to inject a custom ExecutorService into ai.timefold.solver.core.impl.solver.DefaultSolverManager.
Currently, DefaultSolverManager only provides a constructor that initializes an ExecutorService internally:
public DefaultSolverManager(SolverFactory<Solution_> solverFactory, SolverManagerConfig solverManagerConfig) { this.defaultExceptionHandler = (problemId, throwable) -> LOGGER.error("Solving failed for problemId ({}).", problemId, throwable); this.solverFactory = solverFactory; validateSolverFactory(); var parallelSolverCount = solverManagerConfig.resolveParallelSolverCount(); var threadFactoryClass = solverManagerConfig.getThreadFactoryClass(); var threadFactory = threadFactoryClass == null ? Executors.defaultThreadFactory() : ConfigUtils.newInstance(solverManagerConfig, "threadFactoryClass", threadFactoryClass); solverThreadPool = Executors.newFixedThreadPool(parallelSolverCount, threadFactory); problemIdToSolverJobMap = new ConcurrentHashMap<>(parallelSolverCount * 10); }
While I could implement SolverManager myself, this would require rewriting SolverJob, SolverJobBuilder, and other related components - overkill for such a small change.
Use Case:
I'm building a "You are in a queue X/Y" feature, were being able to pass a custom ExecutorService would simplify this significantly. Also this would allow to configure thread pool queue limit, timeouts etc easily.
Would you be open to modifying DefaultSolverManager to allow dependency injection for the ExecutorService? If so, I'm happy to contribute a PR.
Best regards,
Alex
Beta Was this translation helpful? Give feedback.
All reactions