We have observed a JMS message leak using Seam Remoting to subscribe to a JMS topic, whereby the list of undelivered topic messages grows indefinitely until the server ultimately runs out of memory and crashes.
The cause of this seems to be that Seam Remoting requires the web client to manually unsubscribe from topics in order to properly release system resources. This of course cannot be guaranteed.
Consider the following scenario:
- On the server, a new org.jboss.seam.remoting.messaging.RemoteSubscriber is created, which in turn creates a new JMS topic subscriber. The JMS provider will now store any new topic messages until they have been consumed by the web-client.
- Say the web client navigates to a different page (or simply drops out) and therefore never calls Seam.Remoting.unsubscribe() - in this situation the RemoteSubscriber never closes its JMS session and all pending topic messages are queued indefinitely by the JMS provider, ultimately resulting in the server running out memory (or database space if persistent messages are used).
This problem has been observed on JBossAS 4.2.0.GA with JBossMQ and Seam 1.2.1.GA.
It is very easy to reproduce this problem by simply sending persistent messages to the remoting topic and then observing the jms_messages table in your database to see the ever-growing list of messages when the client navigates away from the subcribed page.
It seems someone else has encountered a similar problem (http://www.jboss.org/index.html?module=bb&op=viewtopic&t=92485) which addresses the multiple-subscription issue, however the proposed workaround does not cater for the situation where the client simply navigates away, never to be seen by the again and leaving an open topic subscriber to fill up with messages.
I can think of two possible solutions to this:
- Have some mechanism that gets notified whenever web sessions are deleted by the server and release any associated RemoteSubscribers accordingly, however this does not cater for the scenario where the web session stays valid, but the user has simply navigated away from the page with the topic subscription.
- Another approach may simply be to have some kind of cleanup thread that periodically checks all RemoteSubscribers to identify and unsubscribe any which have not had poll() called on them for a predefined period (say 2 or 3 times the remoting poll timeout defined in components.xml?). Client code may potentially need to be modified to handle resubscribing if its subscription has expired (with possible associated loss of messages), however this would not normally happen as long as the ajax client always commenced a new long-poll as soon as the last one ended.
Perhaps a combination of these two approaches would be the cleanest?