activemq-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Timothy Bish (JIRA)" <j...@apache.org>
Subject [jira] Resolved: (AMQ-3153) An expired message that is consumed and resent with an updated expiration never expires again.
Date Thu, 24 Feb 2011 21:03:39 GMT

     [ https://issues.apache.org/jira/browse/AMQ-3153?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
]

Timothy Bish resolved AMQ-3153.
-------------------------------

       Resolution: Fixed
    Fix Version/s: 5.5.0

Fix in trunk, test added, thanks.

> An expired message that is consumed and resent with an updated expiration never expires
again.
> ----------------------------------------------------------------------------------------------
>
>                 Key: AMQ-3153
>                 URL: https://issues.apache.org/jira/browse/AMQ-3153
>             Project: ActiveMQ
>          Issue Type: Bug
>          Components: Broker
>    Affects Versions: 5.4.2
>            Reporter: Stirling Chow
>            Assignee: Timothy Bish
>             Fix For: 5.5.0
>
>         Attachments: AMQ3513.patch
>
>
> Symptom
> ========
> We have a use case where a producer sends a message to a queue with an expiration.  When
the message expires to the DLQ, a consumer on the DLQ receives the message, modifies it, and
resends it to the original queue with an updated expiration.
> When the expired message is resent, it is given a new JMS message ID, so is, for all
intents and purposes, a new message.  However, althought the resent message has an updated
expiration, it never expires to the DLQ.
> Cause
> =====
> When a message expires, an "originalExpiration" property is added to the message by RegionBroker.stampAsExpired:
>     private boolean stampAsExpired(Message message) throws IOException {
>         boolean stamped=false;
>         if (message.getProperty(ORIGINAL_EXPIRATION) == null) {
>             long expiration=message.getExpiration();     
>             message.setProperty(ORIGINAL_EXPIRATION,new Long(expiration));
>             stamped = true;
>         }
>         return stamped;
>     }
> When the consumer receives and resends the expired message, ActiveMQSession gives the
message a new ID and updates its expiration:
>     protected void send(ActiveMQMessageProducer producer, ActiveMQDestination destination,
Message message, int deliveryMode, int priority, long timeToLive,
>                         MemoryUsage producerWindow, int sendTimeout) throws JMSException
{
> ..
>             long expiration = 0L;
>             if (!producer.getDisableMessageTimestamp()) {
>                 long timeStamp = System.currentTimeMillis();
>                 message.setJMSTimestamp(timeStamp);
>                 if (timeToLive > 0) {
>                     expiration = timeToLive + timeStamp;
>                 }
>             }
>             message.setJMSExpiration(expiration);
> ...
>             // Set the message id.
>             if (msg == message) {
>                 msg.setMessageId(new MessageId(producer.getProducerInfo().getProducerId(),
sequenceNumber));
>             } else {
>                 msg.setMessageId(new MessageId(producer.getProducerInfo().getProducerId(),
sequenceNumber));
>                 message.setJMSMessageID(msg.getMessageId().toString());
>             }
> ...
> At this point the resent message has a new ID and a new expiration, so it should be allowed
to reexpire.  However, the resent message still carries the originalExpiration property, which
makes RegionBroker report the message has not expired (even though it may have):
>     @Override
>     public boolean isExpired(MessageReference messageReference) {
>         boolean expired = false;
>         if (messageReference.isExpired()) {
>             try {
>                 // prevent duplicate expiry processing
>                 Message message = messageReference.getMessage();
>                 synchronized (message) {
>                     expired = stampAsExpired(message);
>                 }
>             } catch (IOException e) {
>                 LOG.warn("unexpected exception on message expiry determination for: "
+ messageReference, e);
>             }
>         }
>         return expired;
>     }
> Since the broker is not reporting the message as expired, the expired message processing
in Queue bypasses the message (from Queue.doBrowse()):
>                                 if (broker.isExpired(node)) {
>                                     LOG.debug("expiring from messages: " + node);
>                                     messageExpired(connectionContext, createMessageReference(node.getMessage()));
>                                 }
>                                 messages.remove();
> Solution
> =======
> Whenever a message is sent to a broker from a message producer, it should have its originalExpiration
property cleared.  I've provided a patch in ActiveMQSession to do this, but I'm not familiar
enough with the workflow to know if this is the appropriate place --- I'm specifically unhappy
with the need to case the javax.jms.Message to an ActiveMQMessage in order to clear the readonly
properties.

-- 
This message is automatically generated by JIRA.
-
For more information on JIRA, see: http://www.atlassian.com/software/jira

        

Mime
View raw message