ARTEMIS-4418 use consumer delivery sequence in messageId for openwire broker sequence id, makes delivery count calculation independent of message order
This commit is contained in:
parent
9864e005d2
commit
91debf25db
|
@ -481,15 +481,16 @@ public final class OpenWireMessageConverter {
|
||||||
public static MessageDispatch createMessageDispatch(MessageReference reference,
|
public static MessageDispatch createMessageDispatch(MessageReference reference,
|
||||||
ICoreMessage message,
|
ICoreMessage message,
|
||||||
WireFormat marshaller,
|
WireFormat marshaller,
|
||||||
AMQConsumer consumer, UUID serverNodeUUID) throws IOException {
|
AMQConsumer consumer,
|
||||||
|
UUID serverNodeUUID,
|
||||||
|
long consumerDeliverySequenceId) throws IOException {
|
||||||
ActiveMQMessage amqMessage = toAMQMessage(reference, message, marshaller, consumer, serverNodeUUID);
|
ActiveMQMessage amqMessage = toAMQMessage(reference, message, marshaller, consumer, serverNodeUUID);
|
||||||
|
|
||||||
//we can use core message id for sequenceId
|
amqMessage.getMessageId().setBrokerSequenceId(consumerDeliverySequenceId);
|
||||||
amqMessage.getMessageId().setBrokerSequenceId(message.getMessageID());
|
|
||||||
MessageDispatch md = new MessageDispatch();
|
MessageDispatch md = new MessageDispatch();
|
||||||
md.setConsumerId(consumer.getId());
|
md.setConsumerId(consumer.getId());
|
||||||
md.setRedeliveryCounter(reference.getDeliveryCount() - 1);
|
md.setRedeliveryCounter(reference.getDeliveryCount() - 1);
|
||||||
md.setDeliverySequenceId(amqMessage.getMessageId().getBrokerSequenceId());
|
md.setDeliverySequenceId(consumerDeliverySequenceId);
|
||||||
md.setMessage(amqMessage);
|
md.setMessage(amqMessage);
|
||||||
ActiveMQDestination destination = amqMessage.getDestination();
|
ActiveMQDestination destination = amqMessage.getDestination();
|
||||||
md.setDestination(destination);
|
md.setDestination(destination);
|
||||||
|
|
|
@ -27,6 +27,7 @@ import java.util.concurrent.ScheduledExecutorService;
|
||||||
import java.util.concurrent.ScheduledFuture;
|
import java.util.concurrent.ScheduledFuture;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
import java.util.concurrent.atomic.AtomicLong;
|
||||||
import java.util.concurrent.atomic.AtomicReference;
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
@ -81,6 +82,7 @@ public class AMQConsumer {
|
||||||
private boolean internalAddress = false;
|
private boolean internalAddress = false;
|
||||||
private volatile Set<MessageReference> rolledbackMessageRefs;
|
private volatile Set<MessageReference> rolledbackMessageRefs;
|
||||||
private ScheduledFuture<?> delayedDispatchPrompter;
|
private ScheduledFuture<?> delayedDispatchPrompter;
|
||||||
|
private AtomicLong deliveredSequenceId = new AtomicLong(0);
|
||||||
|
|
||||||
public AMQConsumer(AMQSession amqSession,
|
public AMQConsumer(AMQSession amqSession,
|
||||||
org.apache.activemq.command.ActiveMQDestination d,
|
org.apache.activemq.command.ActiveMQDestination d,
|
||||||
|
@ -292,7 +294,7 @@ public class AMQConsumer {
|
||||||
message.removeProperty(MessageUtil.CONNECTION_ID_PROPERTY_NAME);
|
message.removeProperty(MessageUtil.CONNECTION_ID_PROPERTY_NAME);
|
||||||
}
|
}
|
||||||
//handleDeliver is performed by an executor (see JBPAPP-6030): any AMQConsumer can share the session.wireFormat()
|
//handleDeliver is performed by an executor (see JBPAPP-6030): any AMQConsumer can share the session.wireFormat()
|
||||||
dispatch = OpenWireMessageConverter.createMessageDispatch(reference, message, session.wireFormat(), this, session.getCoreServer().getNodeManager().getUUID());
|
dispatch = OpenWireMessageConverter.createMessageDispatch(reference, message, session.wireFormat(), this, session.getCoreServer().getNodeManager().getUUID(), deliveredSequenceId.getAndIncrement());
|
||||||
int size = dispatch.getMessage().getSize();
|
int size = dispatch.getMessage().getSize();
|
||||||
reference.setProtocolData(MessageId.class, dispatch.getMessage().getMessageId());
|
reference.setProtocolData(MessageId.class, dispatch.getMessage().getMessageId());
|
||||||
session.deliverMessage(dispatch);
|
session.deliverMessage(dispatch);
|
||||||
|
@ -446,7 +448,7 @@ public class AMQConsumer {
|
||||||
// treat as delivered
|
// treat as delivered
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (ref.getMessageID() <= info.getLastDeliveredSequenceId() && !isRolledBack(ref)) {
|
if (ref.getProtocolData(MessageId.class).getBrokerSequenceId() <= info.getLastDeliveredSequenceId() && !isRolledBack(ref)) {
|
||||||
// treat as delivered
|
// treat as delivered
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -73,7 +73,7 @@ public class OpenWireMessageConverterTest {
|
||||||
AMQConsumer amqConsumer = Mockito.mock(AMQConsumer.class);
|
AMQConsumer amqConsumer = Mockito.mock(AMQConsumer.class);
|
||||||
Mockito.when(amqConsumer.getOpenwireDestination()).thenReturn(destination);
|
Mockito.when(amqConsumer.getOpenwireDestination()).thenReturn(destination);
|
||||||
|
|
||||||
MessageDispatch dispatch = OpenWireMessageConverter.createMessageDispatch(messageReference, msg, openWireFormat, amqConsumer, nodeUUID);
|
MessageDispatch dispatch = OpenWireMessageConverter.createMessageDispatch(messageReference, msg, openWireFormat, amqConsumer, nodeUUID, i);
|
||||||
|
|
||||||
MessageId messageId = dispatch.getMessage().getMessageId();
|
MessageId messageId = dispatch.getMessage().getMessageId();
|
||||||
assertFalse(mqMessageAuditNoSync.isDuplicate(messageId));
|
assertFalse(mqMessageAuditNoSync.isDuplicate(messageId));
|
||||||
|
@ -95,7 +95,7 @@ public class OpenWireMessageConverterTest {
|
||||||
AMQConsumer amqConsumer = Mockito.mock(AMQConsumer.class);
|
AMQConsumer amqConsumer = Mockito.mock(AMQConsumer.class);
|
||||||
Mockito.when(amqConsumer.getOpenwireDestination()).thenReturn(destination);
|
Mockito.when(amqConsumer.getOpenwireDestination()).thenReturn(destination);
|
||||||
|
|
||||||
MessageDispatch dispatch = OpenWireMessageConverter.createMessageDispatch(messageReference, msg, openWireFormat, amqConsumer, nodeUUID);
|
MessageDispatch dispatch = OpenWireMessageConverter.createMessageDispatch(messageReference, msg, openWireFormat, amqConsumer, nodeUUID, i);
|
||||||
|
|
||||||
MessageId messageId = dispatch.getMessage().getMessageId();
|
MessageId messageId = dispatch.getMessage().getMessageId();
|
||||||
assertFalse(mqMessageAuditNoSync.isDuplicate(messageId));
|
assertFalse(mqMessageAuditNoSync.isDuplicate(messageId));
|
||||||
|
@ -114,7 +114,7 @@ public class OpenWireMessageConverterTest {
|
||||||
AMQConsumer amqConsumer = Mockito.mock(AMQConsumer.class);
|
AMQConsumer amqConsumer = Mockito.mock(AMQConsumer.class);
|
||||||
Mockito.when(amqConsumer.getOpenwireDestination()).thenReturn(destination);
|
Mockito.when(amqConsumer.getOpenwireDestination()).thenReturn(destination);
|
||||||
|
|
||||||
MessageDispatch messageDispatch = OpenWireMessageConverter.createMessageDispatch(messageReference, coreMessage, openWireFormat, amqConsumer, nodeUUID);
|
MessageDispatch messageDispatch = OpenWireMessageConverter.createMessageDispatch(messageReference, coreMessage, openWireFormat, amqConsumer, nodeUUID, 0);
|
||||||
|
|
||||||
assertTrue(messageDispatch.getMessage().getProperty(bytesPropertyKey) instanceof String);
|
assertTrue(messageDispatch.getMessage().getProperty(bytesPropertyKey) instanceof String);
|
||||||
}
|
}
|
||||||
|
@ -130,7 +130,7 @@ public class OpenWireMessageConverterTest {
|
||||||
AMQConsumer amqConsumer = Mockito.mock(AMQConsumer.class);
|
AMQConsumer amqConsumer = Mockito.mock(AMQConsumer.class);
|
||||||
Mockito.when(amqConsumer.getOpenwireDestination()).thenReturn(destination);
|
Mockito.when(amqConsumer.getOpenwireDestination()).thenReturn(destination);
|
||||||
|
|
||||||
MessageDispatch marshalled = (MessageDispatch) openWireFormat.unmarshal(openWireFormat.marshal(OpenWireMessageConverter.createMessageDispatch(messageReference, coreMessage, openWireFormat, amqConsumer, nodeUUID)));
|
MessageDispatch marshalled = (MessageDispatch) openWireFormat.unmarshal(openWireFormat.marshal(OpenWireMessageConverter.createMessageDispatch(messageReference, coreMessage, openWireFormat, amqConsumer, nodeUUID, 0)));
|
||||||
assertEquals(5, marshalled.getMessage().getProperties().keySet().size());
|
assertEquals(5, marshalled.getMessage().getProperties().keySet().size());
|
||||||
Message converted = OpenWireMessageConverter.inbound(marshalled.getMessage(), openWireFormat, null);
|
Message converted = OpenWireMessageConverter.inbound(marshalled.getMessage(), openWireFormat, null);
|
||||||
for (int i = 0; i < 5; i++) {
|
for (int i = 0; i < 5; i++) {
|
||||||
|
@ -161,7 +161,7 @@ public class OpenWireMessageConverterTest {
|
||||||
MessageReference messageReference = new MessageReferenceImpl(artemisMessage, Mockito.mock(Queue.class));
|
MessageReference messageReference = new MessageReferenceImpl(artemisMessage, Mockito.mock(Queue.class));
|
||||||
AMQConsumer amqConsumer = Mockito.mock(AMQConsumer.class);
|
AMQConsumer amqConsumer = Mockito.mock(AMQConsumer.class);
|
||||||
Mockito.when(amqConsumer.getOpenwireDestination()).thenReturn(destination);
|
Mockito.when(amqConsumer.getOpenwireDestination()).thenReturn(destination);
|
||||||
MessageDispatch classicMessageDispatch = OpenWireMessageConverter.createMessageDispatch(messageReference, (ICoreMessage) artemisMessage, openWireFormat, amqConsumer, nodeUUID);
|
MessageDispatch classicMessageDispatch = OpenWireMessageConverter.createMessageDispatch(messageReference, (ICoreMessage) artemisMessage, openWireFormat, amqConsumer, nodeUUID, 0);
|
||||||
assertEquals(PRODUCER_ID, classicMessageDispatch.getMessage().getProducerId().toString());
|
assertEquals(PRODUCER_ID, classicMessageDispatch.getMessage().getProducerId().toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -178,7 +178,7 @@ public class OpenWireMessageConverterTest {
|
||||||
MessageReference messageReference = new MessageReferenceImpl(coreMessage, Mockito.mock(Queue.class));
|
MessageReference messageReference = new MessageReferenceImpl(coreMessage, Mockito.mock(Queue.class));
|
||||||
AMQConsumer amqConsumer = Mockito.mock(AMQConsumer.class);
|
AMQConsumer amqConsumer = Mockito.mock(AMQConsumer.class);
|
||||||
Mockito.when(amqConsumer.getOpenwireDestination()).thenReturn(destination);
|
Mockito.when(amqConsumer.getOpenwireDestination()).thenReturn(destination);
|
||||||
MessageDispatch messageDispatch = OpenWireMessageConverter.createMessageDispatch(messageReference, coreMessage, openWireFormat, amqConsumer, nodeUUID);
|
MessageDispatch messageDispatch = OpenWireMessageConverter.createMessageDispatch(messageReference, coreMessage, openWireFormat, amqConsumer, nodeUUID, 0);
|
||||||
assertEquals(PRODUCER_ID, messageDispatch.getMessage().getProducerId().toString());
|
assertEquals(PRODUCER_ID, messageDispatch.getMessage().getProducerId().toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -194,7 +194,7 @@ public class OpenWireMessageConverterTest {
|
||||||
MessageReference messageReference = new MessageReferenceImpl(artemisMessage, Mockito.mock(Queue.class));
|
MessageReference messageReference = new MessageReferenceImpl(artemisMessage, Mockito.mock(Queue.class));
|
||||||
AMQConsumer amqConsumer = Mockito.mock(AMQConsumer.class);
|
AMQConsumer amqConsumer = Mockito.mock(AMQConsumer.class);
|
||||||
Mockito.when(amqConsumer.getOpenwireDestination()).thenReturn(destination);
|
Mockito.when(amqConsumer.getOpenwireDestination()).thenReturn(destination);
|
||||||
MessageDispatch classicMessageDispatch = OpenWireMessageConverter.createMessageDispatch(messageReference, (ICoreMessage) artemisMessage, openWireFormat, amqConsumer, nodeUUID);
|
MessageDispatch classicMessageDispatch = OpenWireMessageConverter.createMessageDispatch(messageReference, (ICoreMessage) artemisMessage, openWireFormat, amqConsumer, nodeUUID, 0);
|
||||||
assertEquals(MESSAGE_ID, classicMessageDispatch.getMessage().getMessageId().toString());
|
assertEquals(MESSAGE_ID, classicMessageDispatch.getMessage().getMessageId().toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -211,7 +211,7 @@ public class OpenWireMessageConverterTest {
|
||||||
MessageReference messageReference = new MessageReferenceImpl(coreMessage, Mockito.mock(Queue.class));
|
MessageReference messageReference = new MessageReferenceImpl(coreMessage, Mockito.mock(Queue.class));
|
||||||
AMQConsumer amqConsumer = Mockito.mock(AMQConsumer.class);
|
AMQConsumer amqConsumer = Mockito.mock(AMQConsumer.class);
|
||||||
Mockito.when(amqConsumer.getOpenwireDestination()).thenReturn(destination);
|
Mockito.when(amqConsumer.getOpenwireDestination()).thenReturn(destination);
|
||||||
MessageDispatch messageDispatch = OpenWireMessageConverter.createMessageDispatch(messageReference, coreMessage, openWireFormat, amqConsumer, nodeUUID);
|
MessageDispatch messageDispatch = OpenWireMessageConverter.createMessageDispatch(messageReference, coreMessage, openWireFormat, amqConsumer, nodeUUID, 0);
|
||||||
assertEquals(MESSAGE_ID, messageDispatch.getMessage().getMessageId().toString());
|
assertEquals(MESSAGE_ID, messageDispatch.getMessage().getMessageId().toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -228,7 +228,7 @@ public class OpenWireMessageConverterTest {
|
||||||
MessageReference messageReference = new MessageReferenceImpl(coreMessage, Mockito.mock(Queue.class));
|
MessageReference messageReference = new MessageReferenceImpl(coreMessage, Mockito.mock(Queue.class));
|
||||||
AMQConsumer amqConsumer = Mockito.mock(AMQConsumer.class);
|
AMQConsumer amqConsumer = Mockito.mock(AMQConsumer.class);
|
||||||
Mockito.when(amqConsumer.getOpenwireDestination()).thenReturn(destination);
|
Mockito.when(amqConsumer.getOpenwireDestination()).thenReturn(destination);
|
||||||
MessageDispatch messageDispatch = OpenWireMessageConverter.createMessageDispatch(messageReference, coreMessage, openWireFormat, amqConsumer, nodeUUID);
|
MessageDispatch messageDispatch = OpenWireMessageConverter.createMessageDispatch(messageReference, coreMessage, openWireFormat, amqConsumer, nodeUUID, 0);
|
||||||
assertEquals("queue://" + DESTINATION, messageDispatch.getMessage().getOriginalDestination().toString());
|
assertEquals("queue://" + DESTINATION, messageDispatch.getMessage().getOriginalDestination().toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -245,7 +245,7 @@ public class OpenWireMessageConverterTest {
|
||||||
MessageReference messageReference = new MessageReferenceImpl(coreMessage, Mockito.mock(Queue.class));
|
MessageReference messageReference = new MessageReferenceImpl(coreMessage, Mockito.mock(Queue.class));
|
||||||
AMQConsumer amqConsumer = Mockito.mock(AMQConsumer.class);
|
AMQConsumer amqConsumer = Mockito.mock(AMQConsumer.class);
|
||||||
Mockito.when(amqConsumer.getOpenwireDestination()).thenReturn(destination);
|
Mockito.when(amqConsumer.getOpenwireDestination()).thenReturn(destination);
|
||||||
MessageDispatch messageDispatch = OpenWireMessageConverter.createMessageDispatch(messageReference, coreMessage, openWireFormat, amqConsumer, nodeUUID);
|
MessageDispatch messageDispatch = OpenWireMessageConverter.createMessageDispatch(messageReference, coreMessage, openWireFormat, amqConsumer, nodeUUID, 0);
|
||||||
assertEquals("queue://" + DESTINATION, messageDispatch.getMessage().getReplyTo().toString());
|
assertEquals("queue://" + DESTINATION, messageDispatch.getMessage().getReplyTo().toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -269,7 +269,7 @@ public class OpenWireMessageConverterTest {
|
||||||
AMQConsumer amqConsumer = Mockito.mock(AMQConsumer.class);
|
AMQConsumer amqConsumer = Mockito.mock(AMQConsumer.class);
|
||||||
Mockito.when(amqConsumer.getOpenwireDestination()).thenReturn(destination);
|
Mockito.when(amqConsumer.getOpenwireDestination()).thenReturn(destination);
|
||||||
|
|
||||||
MessageDispatch messageDispatch = OpenWireMessageConverter.createMessageDispatch(messageReference, coreMessage, openWireFormat, amqConsumer, nodeUUID);
|
MessageDispatch messageDispatch = OpenWireMessageConverter.createMessageDispatch(messageReference, coreMessage, openWireFormat, amqConsumer, nodeUUID, 0);
|
||||||
|
|
||||||
assertNull(messageDispatch.getMessage().getProperty(hdrArrival));
|
assertNull(messageDispatch.getMessage().getProperty(hdrArrival));
|
||||||
assertNull(messageDispatch.getMessage().getProperty(hdrBrokerInTime));
|
assertNull(messageDispatch.getMessage().getProperty(hdrBrokerInTime));
|
||||||
|
|
|
@ -656,6 +656,7 @@ public class ServerConsumerImpl implements ServerConsumer, ReadyListener {
|
||||||
browserDeliverer.close();
|
browserDeliverer.close();
|
||||||
} else {
|
} else {
|
||||||
messageQueue.removeConsumer(this);
|
messageQueue.removeConsumer(this);
|
||||||
|
messageQueue.deliverAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
session.removeConsumer(id);
|
session.removeConsumer(id);
|
||||||
|
|
|
@ -55,11 +55,20 @@ public class PrefetchRedeliveryCountOpenwireTest extends OpenWireTestBase {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(timeout = 60_000)
|
@Test(timeout = 60_000)
|
||||||
public void testConsumerSingleMessageLoop() throws Exception {
|
public void testConsumerSingleMessageLoopExclusive() throws Exception {
|
||||||
|
doTestConsumerSingleMessageLoop(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(timeout = 60_000)
|
||||||
|
public void testConsumerSingleMessageLoopNonExclusive() throws Exception {
|
||||||
|
doTestConsumerSingleMessageLoop(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void doTestConsumerSingleMessageLoop(boolean exclusive) throws Exception {
|
||||||
Connection exConn = null;
|
Connection exConn = null;
|
||||||
|
|
||||||
SimpleString durableQueue = new SimpleString("exampleQueue");
|
SimpleString durableQueue = new SimpleString("exampleQueue");
|
||||||
this.server.createQueue(new QueueConfiguration(durableQueue).setRoutingType(RoutingType.ANYCAST).setExclusive(true));
|
this.server.createQueue(new QueueConfiguration(durableQueue).setRoutingType(RoutingType.ANYCAST).setExclusive(exclusive));
|
||||||
|
|
||||||
try {
|
try {
|
||||||
ActiveMQConnectionFactory exFact = new ActiveMQConnectionFactory();
|
ActiveMQConnectionFactory exFact = new ActiveMQConnectionFactory();
|
||||||
|
@ -157,6 +166,7 @@ public class PrefetchRedeliveryCountOpenwireTest extends OpenWireTestBase {
|
||||||
}
|
}
|
||||||
session.commit();
|
session.commit();
|
||||||
|
|
||||||
|
// force a local socket close such that the broker sees an exception on the connection and fails the consumer via close
|
||||||
((FailoverTransport)((org.apache.activemq.ActiveMQConnection)exConn).getTransport().narrow(FailoverTransport.class)).stop();
|
((FailoverTransport)((org.apache.activemq.ActiveMQConnection)exConn).getTransport().narrow(FailoverTransport.class)).stop();
|
||||||
exConn.close();
|
exConn.close();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue