allthingssecurity opened a new pull request, #27799: URL: https://github.com/apache/camel/pull/27799
# Description [CAMEL-25612](https://issues.apache.org/jira/browse/CAMEL-25612) `SimpleMessageListenerContainer.initConsumers` assigned the sets of sessions and consumers before it filled them. When `createSession` or `createMessageConsumer` threw, the sets stayed, empty or half filled. During connection recovery that was permanent: 1. attempt n creates the new connection, assigns the sets, one create call fails, the attempt fails (WARN) and is repeated after `recoveryInterval`; 2. attempt n+1 closes that connection (and the sessions of attempt n with it), creates another one, finds `consumers != null`, creates nothing, and reports success. The route stayed started with a started connection and no consumer. Nothing above DEBUG was logged after the WARN of attempt n, no further recovery was scheduled, and no message was consumed until the route or the context was restarted. The reply listeners of the InOut producer use the same container. A create call fails on a fresh connection when the connection fails again while the consumers are created (broker still restarting, failover) and `onException` of that failure arrives before `initConsumers` assigns the sets, or when the connection is fine and the destination or the permission is not there yet (then no `onException` follows, and every such failure ends this way). Changes, all in `SimpleMessageListenerContainer`: - `initConsumers` closes what it created and sets the two fields back to `null` when the loop fails, so the next attempt creates all the consumers. - The same `catch` block closes the session whose consumer could not be created when the container fails to start. That session stayed open on the connection, which is kept for the next start. - `recoverConnection` runs another attempt (it returns `false`, so the task runs again after `recoveryInterval`) when `onException` dropped the consumers while the attempt was creating them. `onException` does not schedule a recovery while one is running. On main this case mostly worked by accident: the loop added to the fields that `onException` had set to `null`, and the `NullPointerException` failed the attempt. The loop no longer fails that way, so the check is needed. Only an `onException` after the last pass of the loop was lost on main; that window is closed too. No new retry loop and no new log per attempt: the attempts are those of the existing recovery task, one WARN line without a stack trace per failed attempt as before; the new case logs at DEBUG. No upgrade guide entry: nothing a route can rely on changes. Tests: - New `SjmsConsumerRecoveryFailedAttemptTest` (4 tests) with the embedded Artemis broker of the module and a connection factory that tracks the connections, sessions and consumers of the route and can make one create call fail. `concurrentConsumers=3`, `recoveryInterval=200`. - After a simulated connection failure the first session (one test) or the last session (another test) of the next connection cannot be created. The test waits for the attempt after that (the third connection), sends a message and expects it, then expects 3 consumers on the third connection. - A container that fails to start because its second consumer cannot be created leaves no open session and no open consumer; a second start creates both consumers on the same connection. - `onException` during the creation of the last session of the recovery connection: another attempt runs and the consumers are on a third connection. - Without the change (main's `SimpleMessageListenerContainer`, same test) three of the four fail: `mock://first Received message count. Expected: <1> but was: <0>`, `mock://last Received message count. Expected: <1> but was: <0>`, and `open sessions after the failed start ==> expected: <0> but was: <1>`. The fourth one (`onException` during the creation) passes on main, through the `NullPointerException` described above; it is there because the loop no longer fails that way. - With the change, camel-sjms tests pass: 138 run, 0 failures, 5 skipped. What was not run: camel-sjms2 (it uses the same container), and no broker other than the embedded Artemis. The failing create call is simulated by the connection factory of the test. Notes: - The open pull request #27173 (CAMEL-16039) changes `onException` in the same file: it moves the three lines that reset the fields into a method. It does not touch `initConsumers` or `recoverConnection`, and the two changes merge without a conflict today. - How it was found: a small TLA+ model of the container (connection alive or failed, the pending `onException` call, the `consumers` field, the consumers on the current connection, the steps of one recovery attempt). For main it reaches a state with a live connection, no consumer and no recovery scheduled, after two connection failures or after one connection failure and one failing create call. The model is only a sketch of the code; the test above is the evidence. # Target - [x] I checked that the commit is targeting the correct branch (Camel 4 uses the `main` branch) # Tracking - [ ] 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). (The ticket is drafted and not filed yet; CAMEL-25612 is a placeholder until it is.) # 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 and tested camel-sjms, including the formatter and import-sort plugins. 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]
