Skip to content

Close the producer sendTopicMessage creates - #1850

Merged
jcschaff merged 1 commit into
masterfrom
fix/jms-topic-producer-close
Aug 7, 2026
Merged

Close the producer sendTopicMessage creates#1850
jcschaff merged 1 commit into
masterfrom
fix/jms-topic-producer-close

Conversation

@jcschaff

@jcschaff jcschaff commented Aug 7, 2026

Copy link
Copy Markdown
Member

Last of the JMS resource problems found while working through the export-progress incident
(#1837, #1838, #1839, #1842, #1844, #1845, and the consumer-close PR this follows).

The leak

sendQueueMessage has always closed its MessageProducer in a finally. sendTopicMessage
never did:

MessageProducer producer = jmsSession.createProducer(jmsSession.createTopic(topic.getName()));
producer.send(jmsMessage.getJmsMessage());
if (bIndependent) { jmsSession.commit(); }
// ... and that was the end of the method

Every publish left a producer on the session.

Why it matters

The sessions doing the publishing are long-lived, so nothing ever cleaned them up:

caller destination session
SimDataServer — data events, export events ClientStatusTopic createProducerSession() at startup
SimulationStateMachine ServiceControlTopic long-lived
StatusMessage.sendToClient ClientStatusTopic caller's session

One leaked producer per status update, for the life of the server — including every export
progress event, which is what made the original incident's message storm expensive in the
first place.

Verification

sendTopicMessageDoesNotLeakProducers publishes five messages and requires the producer
count to return to zero. Control, with the production file reverted and the test kept:

every publish must close the producer it created ==> expected: <0> but was: <5>

Five publishes, five leaked producers.

The count is taken in-process, by wrapping the JMS objects in proxies that tally
createProducer against close, rather than querying the broker or turning on JMX. That is
deliberate: broker-side producer registration is asynchronous, and a count that depends on it
would be exactly the kind of racy assertion that passed locally and failed in CI earlier in
this series. This one is exact.

vcell-server Fast group: 62 passed.

🤖 Generated with Claude Code

https://claude.ai/code/session_01SY1XHgTZXZPqUECo2VBAWg

sendQueueMessage has always closed its MessageProducer in a finally;
sendTopicMessage never did, so every publish left one on the session.

That matters because the sessions doing the publishing are long-lived:
SimDataServer publishes every data and export event to ClientStatusTopic on a
session created at startup, and SimulationStateMachine and StatusMessage do the
same. The producers accumulated for the life of the server -- one per status
update, including every export progress event.

Counting producers opened and closed in-process, five publishes leaked five
producers before this change.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SY1XHgTZXZPqUECo2VBAWg
@jcschaff
jcschaff merged commit ec7f8b6 into master Aug 7, 2026
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant