davsclaus opened a new pull request, #28902:
URL: https://github.com/apache/camel/pull/28902

   Fixes [CAMEL-26123](https://issues.apache.org/jira/browse/CAMEL-26123).
   
   ### 1. With `configFile`, a new `SolverManager` per exchange that is never 
closed
   
   **Was wrong:** with `configFile` and no `SolverManager` (neither the 
`solverManager` option nor the `CamelOptaPlannerSolverManager` header), 
`OptaPlannerProducer.getSolverManager` built a new `SolverConfig`, 
`SolverFactory` and `SolverManager` for every exchange and never closed it. 
Each one keeps a fixed thread pool, so every exchange left a solver thread 
behind. It also meant a `ProblemChange` sent to that endpoint went to a fresh 
`SolverManager` that was not solving anything.
   
   **Changed:** `OptaPlannerEndpoint.getOrCreateSolverManager()` creates the 
`SolverManager` once, on first use, and `doStop` closes it. It stays lazy 
because `configFile` defaults to the path of the URI, so it must not be loaded 
when a `SolverManager` comes from the option or the header.
   
   ### 2. Solvers and listeners in JVM-wide static maps
   
   **Was wrong:** `OptaPlannerEndpoint` kept `SOLVERS` and `SOLUTION_LISTENER` 
in static maps, the listeners keyed only by `problemId` (default `1`). A 
consumer in any `CamelContext` of the JVM got the best solutions of every 
producer with the same `problemId`. Also, stopping any endpoint terminated the 
solvers of all endpoints.
   
   **Changed:** the listeners are now kept on `OptaPlannerComponent` (one per 
`CamelContext`), still keyed by `problemId`. They stay at component level, not 
per endpoint, because the producer and consumer usually have different URIs 
(`async=true` on the producer only), so they are different endpoints. The 
listener sets are now `CopyOnWriteArraySet` (they were a plain `HashSet` 
iterated from solver threads while consumers add and remove). The `solvers` map 
is now an instance field.
   
   ### 3. Sync mode sent no events to consumers
   
   **Was wrong:** with `async=false` the producer called 
`solverManager.solve(problemId, body)` without a best solution listener, so a 
consumer on the same `problemId` got no events.
   
   **Changed:** the sync path now uses `solveAndListen` with the same 
`OptaplannerEventSupport` as the async path, and still waits for the final best 
solution.
   
   ### Tests
   
   Three new tests. Each one failed on `main` and passes with the fix:
   
   - `OptaPlannerConfigFileSolverManagerTest`: sends more sync exchanges than 
one `SolverManager` has solver threads. It then checks that the number of live 
`pool-N-thread-M` threads grows by at most `parallelSolverCount`, and that it 
goes back to the baseline after the context stops. On main it timed out because 
one thread leaked per exchange.
   - `OptaPlannerConsumerCamelContextTest`: a consumer in a second 
`CamelContext` with the same `problemId` gets no event. On main it got the 
events of the first context.
   - `OptaPlannerSyncConsumerTest`: a consumer gets the best solutions of a 
sync producer. On main it got 0 messages.
   
   The new tests use `solverConfigQuick.xml`, a copy of the test solver config 
with a 200 ms limit instead of 10 s. `mvn clean install -Psourcecheck` in the 
module: 10 tests, 0 failures.
   
   ### Docs and generated files
   
   - Component doc: the consumer section says that events come from sync and 
async producers of the same `CamelContext`. A new paragraph says how the 
`configFile` `SolverManager` is shared and closed.
   - `configFile` option description and the `consumerOut` body type 
description are updated. Regenerated `optaplanner.json`, the catalog copies 
(json + adoc) and the endpoint DSL.
   - Upgrade guide 4.24: new `camel-optaplanner` section. A shared 
`SolverManager` means that solving a problem while another one with the same 
`problemId` is still being solved on the same endpoint now fails with `The 
problemId (1) is already solving`. That was already the case with a 
`SolverManager` you configure. Before, each exchange had its own leaking 
manager, so concurrent solves of the same `problemId` happened to work. The 
section also covers the per-context consumers and the sync events.
   
   ### Not changed
   
   - Listeners are still keyed by `problemId` only, within a `CamelContext`. 
Two producers with different `SolverManager`s and the same `problemId` in one 
context still feed the same consumers. Keying by `problemName` as well would 
break routes whose consumer URI uses another name than the producer.
   - The unused protected `getOrCreateSolver` / `createSolver` / `getSolver` 
methods are kept (now per endpoint), so subclasses still compile.
   
   _Claude Code on behalf of Claus Ibsen (davsclaus)_
   
   🤖 Generated with [Claude Code](https://claude.com/claude-code)
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to