java: a refused listener subscription closes the connection it started (#7264) - #7267
Open
delchev wants to merge 1 commit into
Open
java: a refused listener subscription closes the connection it started (#7264)#7267delchev wants to merge 1 commit into
delchev wants to merge 1 commit into
Conversation
#7264) The connection factory start()s the connection before returning it, so a refusal that arrives after that - the session, the destination, the redelivery policy, the durable subscriber, the listener - leaves a live transport socket and its ActiveMQ thread behind. The catch reported the failure and returned null without closing it. Before the reconciliation retry (#7220) that cost one orphaned connection per refused subscription per rebuild. Now the attach repeats every 30 seconds for as long as the refusal lasts, and the realistic refusals at exactly this point are permanent ones - an external broker whose destination authorization refuses createDurableSubscriber with a JMSSecurityException, or a destination name its policy rejects - so the retry manufactures the outage it was added to prevent: one started connection per subscription per tenant per tick until the file-descriptor or thread limit is reached. The connection is held in a local declared before the try and closed in the catch. The close failure is DEBUG: the refusal is already reported and a broker that just said no is likely to refuse the close too, so it must not add a second line per tick to a lasting outage. Three retry-test cases cover it - none of the existing ones makes anything after createConnection throw. Closing an attempt is also not recording it: the subscription still opens on the first pass the broker accepts.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #7264
ActiveMQConnectionArtifactsFactory.createConnectionstart()s the connection before returning it, so by the timecreateSession/createTopic/configureRedeliveryPolicy/createDurableSubscriber/setMessageListenercan throw, a transport socket and its ActiveMQ thread exist. ThecatchinListenerClassConsumer.subscribereported the failure and returnednullwithout closing them.Before #7220 that ran once per rebuild, so the cost was one orphaned connection per refused subscription. Now
JavaConsumersReconcilerre-runssubscribeevery 30 s for as long as the refusal lasts, and the realistic refusals at exactly this point are permanent: an external broker (DIRIGIBLE_MESSAGING_BROKER_URL) whose destination authorization refuses the consumer with aJMSSecurityException, or a destination name its policy rejects. One started connection per subscription per tenant per tick, at DEBUG after the first WARN — an outage the retry itself manufactures.Change
connectionis held in a local declared before thetry, and thecatchcalls a newcloseQuietly(label, connection).Tests
Three cases in
ListenerClassConsumerRetryTest— none of the existing ones makes anything aftercreateConnectionthrow, so the path was untested. The mock factory now hands out the connection and refuses the session with aJMSSecurityException, which is where a broker's destination authorization really says no:aRefusalAfterTheConnectionWasStartedClosesIt— nothing subscribed, and both tenants' connections closed.everyRetryOfALastingRefusalClosesItsOwnConnection— three passes close three per tenant; the retry accumulates nothing.theSubscriptionStillOpensAfterAClosedAttempt— closing an attempt is not recording it; the subscription opens once on the first pass the broker accepts.mvn -pl components/engine/engine-java test -Dtest='ListenerClassConsumer*Test'→ 24 tests, all green.formatter:validateand thereleasejavadoc profile pass on the module.🤖 Generated with Claude Code