activemq-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Gary Tully (JIRA)" <>
Subject [jira] Commented: (AMQ-2552) Automatic message expiration may not occur on a queue with no (or slow) consumers.
Date Mon, 04 Jan 2010 17:31:15 GMT


Gary Tully commented on AMQ-2552:

Have you played with maxExpirePageSize > 400, the intent is that a larger value of this
will force the browse to examine more than a page full of messages but will not keep them
in memory. 
The problem of timely processing of messages at the end of the queue is still an issue though.
It may be possible to remember the last checked message id and implement a moving window on
subsequent processing. That would require support in the cursor for setting that start point
which is not currently exposed. It is there under the covers though so it is worth a look.
The down side is that it will kill performance (in the case of concurrent dispatch) as it
will lock the cursor. 

btw: I agree that the browse idiom is not ideal but it is consistent with existing cursor
usage. The main difficulty in a ideal solution is synchronization with message dispatch and
acking. For that reason, I think 6.0 is the place for the ideal solution.

> Automatic message expiration may not occur on a queue with no (or slow) consumers.
> ----------------------------------------------------------------------------------
>                 Key: AMQ-2552
>                 URL:
>             Project: ActiveMQ
>          Issue Type: Bug
>          Components: Broker
>    Affects Versions: 5.3.1
>         Environment: ActiveMQ 5.3.1 Snapshot r893661
>            Reporter: Stirling Chow
>         Attachments:
> Symptom
> ========
> If a queue is loaded with 400+ messages that never expire, and then a message that does
expire is added to the end of the queue, the added message will not be processed by the Broker's
expiration logic until some of the 400+ unexpired messages are consumed.  A unit test is provided
to demonstrate this issue.
> These test cases worked for AMQ 5.3, but not for AMQ 5.3.1-SNAPSHOT r893661.
> Motivation
> ========
> Our application uses message expiration to trigger actions when messages are left in
a queue for too long a period.  In many cases, there are no consumers on the queue containing
the messages that might expire.  Prior versions of AMQ only expired messages when an attempt
was made to dispatch them to a consumer, but AMQ-1112 introduced the notion of periodic, automatic
expiration of pending messages (see the expireMessagesPeriod policy).  With this periodic
expiration, our expectation is that expired messages will be detected and processed in a timely
fashion, regardless of the presence of consumers on the queue.
> Cause
> ======
> AMQ-2481 removed forced paging from the periodically-called expireMessages() method:
> >>
>         doBrowse(true, browsedMessages, this.getMaxExpirePageSize());
> <<
>         doBrowse(browsedMessages, this.getMaxExpirePageSize());
> The purpose of the change was to limit the number of messages that would be paged into
memory from the message store.  The side effect is that only the first 400 messages in the
queue are ever inspected by expireMessages().  If these 400 messages do not contain the messages
that are expiring and there are no active consumers to move the expiring messages forward,
then expiration will never occur.  With AMQ 5.3, successive calls to expireMessages() would
eventually pull all messages into the page so they could be checked for expiration.
> It should also be noted that the test cases can be modified so there is a consumer (with
a selector that doesn't choose any of the messages), and they still fail showing that the
issue is not purely the result of having *no* consumers.
> Resolution
> =========
> I don't think the browse idiom works very well for the automated expiration task.  It
was my initial assumption (and expectation) that the expireMessagesPeriod task would process
*all* expired messages in the queue *each time* the task fired.  A related issue to limiting
the number of messages that are examined during each expiration task is that expiring messages
at the end of the queue will not be handled in a timely fashion since they must wait for multiple
firings of the expiration task (this is on 5.3 code; 5.3.1 code will never get to those messages).
> If the desire/need is to scan all messages to determine which have expired, the existing
paging strategy is limited because it would require all messages to be brought from store
into memory, thus defeating the whole point of paging.  An alternative might be to have a
sliding page window that would allow batches of messages to be brought in while clearing out
the previous batch.
> Another solution might be to have the expiration task page in directly from the store,
but this is problematic since non-persistent messages would still have to come in from the
pending message cursor.  In addition, a complete scan of the store might be non-performant
for large queues.
> I think the most satisfactory solution for minimizing unnecessary processing and providing
timely expiration of messages is to implement a proper heap that indexes messages with expiration
values and allows immediate access to *only* the messages that have expired.  The references
to these expired messages could then be used to remove the messages directly from the cursors
and the store rather than having to iterate over these structures.

This message is automatically generated by JIRA.
You can reply to this email to add a comment to the issue online.

View raw message