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

   # Description
   
   [CAMEL-26049](https://issues.apache.org/jira/browse/CAMEL-26049)
   
   Two resource leaks in camel-coap, both because Californium 3.14 only 
releases threads and sockets on `destroy()`:
   
   1. `CoAPComponent.doStop` calls `stop()` on each `CoapServer` of its 
`servers` map, never `destroy()`, and keeps the map. `CoapServer.stop()` stops 
the endpoints but keeps the server's executors (`CoapServer(main)#N`, 
`CoapServer(secondary)#N`), whose threads are not daemon threads; only 
`destroy()` shuts them down. So after a CamelContext with a coap consumer is 
stopped, the JVM does not exit on its own (a standalone or Camel Main 
application, or a container that then needs a SIGKILL after the grace period), 
and every CamelContext started in the same JVM adds 3 more threads.
   2. `CoAPProducer` creates its `CoapClient` on the first exchange with 
`CoAPEndpoint.createCoapClient`, which builds the client's own `CoapEndpoint` 
(a bound UDP socket with its receiver and sender threads, or the DTLS/TCP 
connector threads). `doStop` calls `client.shutdown()`, which in Californium 
3.14 only shuts down the client's executors (read with javap) and does not 
destroy an endpoint set with `setEndpoint`. A route restart creates a new 
producer, so each restart (and each producer evicted from a `toD` or 
`ProducerTemplate` cache) leaks a bound socket and 2 or more threads.
   
   Changes:
   - `CoAPComponent.doStop` calls `destroy()` on the servers and clears the 
map. The consumers get their server from `getServer` on each start, so a 
CamelContext started again creates the servers again. `doStop` runs under the 
service lock that `getServer` also uses.
   - `CoAPProducer.doStop` destroys the endpoint of the client it created 
(after `client.shutdown()`). A client set on the component or the endpoint 
(`client` option) is not created by the producer and is left alone, as before.
   - A rare case changes: a producer that is stopped while another thread still 
has a request in flight on it, for example a producer that a `toD` or 
`ProducerTemplate` cache evicts while it is in use (a graceful route stop waits 
for the inflight exchanges first). Its endpoint is now destroyed, so that 
request gets no response: it waits until the client timeout or returns null 
earlier, and the exchange fails. On main only `client.shutdown()` ran, and the 
response still arrived. The error message then reads `client.getURI()` after 
`doStop` set `client` to null, which is a `NullPointerException`; that could 
already happen on main when no response came.
   - No option or generated file change. No upgrade guide entry: nothing for 
users to change.
   - Backport: camel-4.23.x, 4.22.x, 4.18.x and 4.14.x have the same code.
   
   Not changed (follow-up JIRAs if wanted):
   - The observe consumer (`CoAPObserver`, `observe=true`) also only calls 
`client.shutdown()` and keeps its client endpoint. There the endpoint must stay 
until the cancel request that `doStop` sends (`proactiveCancel()`, CAMEL-25742) 
has gone out, so destroying it right after the cancel is not the same small 
change.
   - `CoAPConsumer` has no `doStop`: a stopped route stays registered on its 
resource until another consumer takes the path.
   
   Tests:
   - New `CoAPComponentStopDestroysServersTest`, 2 tests, and 
`CoAPProducerStopDestroysEndpointTest`, 1 test, JUnit assertions as in the 
module.
   - `stoppingTheCamelContextReleasesTheServerThreads` (own 
`DefaultCamelContext` with a coap consumer, one GET, `stop()`) fails on main: 
`non-daemon CoapServer threads still alive after CamelContext.stop() ==> 
expected: <[]> but was: <[CoapServer(main)#1, CoapServer(secondary)#1, 
CoapServer(secondary)#2]>`.
   - `aCamelContextStartedAgainServesAgain` is a control that passes on main 
and with the fix: the server is created again after a context stop and start.
   - `routeRestartsReleaseTheEndpointsOfTheStoppedProducers` (5 restarts of a 
producer route, a request after each, then a stop) fails on main: `UDP receiver 
threads of stopped CoAP producers still alive after 5 restarts ==> expected: 
<0> but was: <10>`.
   - Unit tests of camel-coap with the fix: 85 run, 0 failures, 0 skipped 
(including the observe restart tests of CAMEL-25742).
   - The formatter and import-sort plugins ran. I built offline with 
`-Dasm-version=9.11` because asm 9.11.1 was not in my local repository.
   
   # Target
   
   - [x] I checked that the commit is targeting the correct branch (Camel 4 
uses the `main` branch)
   
   # Tracking
   - [x] If this is a large change, bug fix, or code improvement, I checked 
there is a [JIRA issue](https://issues.apache.org/jira/browse/CAMEL) filed for 
the change (usually before you start working on it): 
[CAMEL-26049](https://issues.apache.org/jira/browse/CAMEL-26049).
   
   # Apache Camel coding standards and style
   
   - [x] I checked that each commit in the pull request has a meaningful 
subject line and body.
   - [ ] I have run `mvn clean install -DskipTests` locally from root folder 
and I have committed all auto-generated changes.
     (I built camel-coap and ran its tests, including the formatter and 
import-sort plugins. No generated file changes. I did not run the full root 
build.)
   
   # AI-assisted contributions
   
   - [x] If this PR includes AI-generated code, commits have proper 
co-authorship attribution (e.g., `Co-authored-by` trailers) and the PR 
description identifies the AI tool used.
     This PR was prepared with Claude Code (Claude Opus 5.5). The commit 
carries a `Co-Authored-By` trailer.
   
   _Claude Code on behalf of allthingssecurity_
   
   🤖 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