2

What am I missing?

AMQ version 5.13.2 Java 1.8.0_74 Windows 10

Given a simple test case, two Object messages are transmitted, one with data and the other being an end-of-data marker. Only the end-of-data marker is being received.

The queue is created at the beginning of the job, and destroyed after the job completes.

If I run a larger number of transactions, I see about a 50% receive rate.

The logs clearly show that the receiver was started before the first message was put on the queue, both messages are being put on the queue, but only the second message is actually being received.

Both the sender and receiver are on the same JVM. Each has its own Session and Connection.

Connection and queue Setup Code:

@Override
public void beforeJob(JobExecution jobExecution) {
    // TODO Auto-generated method stub
    try {
        jobParameters = jobExecution.getJobParameters();

        readerConnection = connectionFactory.createConnection();
        readerConnection.start();

        writerConnection = connectionFactory.createConnection();
        writerConnection.start();

        jmsQueueManagementSession = writerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE);

        queueName = jobParameters.getString("jobName") + "." + jobExecution.getId();

        queue = jmsQueueManagementSession.createQueue(getQueueName());

    } catch (JMSException ex) {
        throw new MaxisRuntimeException(
                MaxisCodeHelperImpl.generateCode("MXAR", MXMODULE, JMS_RECEIVER_INITIALIZATION_ERROR), null);
    }

}

Sender setup code:

@Override
public void beforeStep(StepExecution stepExecution) {

    this.stepExecution = stepExecution;
    this.setJobExecution(stepExecution.getJobExecution());
    try {
        this.connection = jmsJobExecutionListener.getWriterConnection();
        this.session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
        this.messageProducer = session.createProducer(jmsJobExecutionListener.getQueue());
    } catch (JMSException ex) {
        throw new RuntimeException(ex.getMessage(), ex);
    }
}

Receiver setup Code:

@Override
@BeforeStep
public void beforeStep(StepExecution stepExecution) {
    this.stepExecution = stepExecution;
    this.setJobExecution(stepExecution.getJobExecution());
    try {
        this.connection = jmsJobExecutionListener.getReaderConnection();
        this.jmsSession = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
        this.messageConsumer = jmsSession.createConsumer(jmsJobExecutionListener.getQueue());
    }
    catch (JMSException ex)
    {
        throw new RuntimeException(ex.getMessage(), ex);
    }

}

Transmit code:

    private void doSomeStuffInTransaction (final Object model) {
        transactionTemplate.execute(new TransactionCallbackWithoutResult() {
            @Override
            protected void doInTransactionWithoutResult(TransactionStatus status) {
                try {
                    doSomeStuff ( model );

                    ObjectMessage message = session.createObjectMessage(
                            (model.getRoot() == null)
                            ? null
                            : model.getRoot().getContents().getId());
                    messageProducer.send(message);
                    logger.debug("Sent: {}", message.toString());
                }catch (Exception e) {
                      //use this to rollback exception in case of exception
                    status.setRollbackOnly();
                    throw new RuntimeException(e.getmessage(), e);
                }   

            }});
    }   

Receiver code:

public Object read() throws Exception,
        UnexpectedInputException, ParseException,
        NonTransientResourceException {

    Object result = null;

    logger.debug("Attempting to receive message on connection: ", connection.toString());

    ObjectMessage msg = (ObjectMessage) messageConsumer.receive();
    logger.debug("Received: {}", msg.toString());
    result = msg.getObject();

    return result;
}

Log snip:

DEBUG com.mylib.SelectedDataJmsReader - Attempting to receive message on connection: 
... snip ...
*** First message ***
DEBUG org.apache.activemq.broker.region.Queue - localhost Message ID:zip-56502-1457640572818-4:2:2:1:1 sent to queue://Stuff via SQL.402
DEBUG org.apache.activemq.broker.region.Queue - queue://Stuff via SQL.402, subscriptions=2, memory=0%, size=1, pending=0 toPageIn: 1, Inflight: 0, pagedInMessages.size 0, pagedInPendingDispatch.size 0, enqueueCount: 1, dequeueCount: 0, memUsage:2214
DEBUG com.maxis.mxmove.core.SelectedDataJmsWriter - Sent: ActiveMQObjectMessage {commandId = 0, responseRequired = false, messageId = ID:zip-56502-1457640572818-4:2:2:1:1, originalDestination = null, originalTransactionId = null, producerId = null, destination = queue://Stuff via SQL.402, transactionId = null, expiration = 0, timestamp = 1457640610215, arrival = 0, brokerInTime = 0, brokerOutTime = 0, correlationId = null, replyTo = null, persistent = true, type = null, priority = 4, groupID = null, groupSequence = 0, targetConsumerId = null, compressed = false, userID = null, content = org.apache.activemq.util.ByteSequence@78cb27fd, marshalledProperties = null, dataStructure = null, redeliveryCounter = 0, size = 0, properties = null, readOnlyProperties = false, readOnlyBody = false, droppable = false, jmsXGroupFirstForConsumer = false}
INFO  com.maxis.mxmove.core.SelectedDataJmsWriter - Committed 1 stuff to redo log and JMS queue

*** Second Message ***
INFO  com.maxis.mxmove.core.SourceSelectionReaderImpl - Returning empty stuff and end-of-stream placeholder.
DEBUG org.apache.activemq.broker.region.Queue - localhost Message ID:zip-56502-1457640572818-4:2:2:1:2 sent to queue://Stuff via SQL.402
DEBUG org.apache.activemq.broker.region.Queue - queue://Stuff via SQL.402, subscriptions=2, memory=0%, size=2, pending=0 toPageIn: 1, Inflight: 1, pagedInMessages.size 1, pagedInPendingDispatch.size 0, enqueueCount: 2, dequeueCount: 0, memUsage:3155
DEBUG com.maxis.mxmove.core.SelectedDataJmsWriter - Sent: ActiveMQObjectMessage {commandId = 0, responseRequired = false, messageId = ID:zip-56502-1457640572818-4:2:2:1:2, originalDestination = null, originalTransactionId = null, producerId = null, destination = queue://Stuff via SQL.402, transactionId = null, expiration = 0, timestamp = 1457640610375, arrival = 0, brokerInTime = 0, brokerOutTime = 0, correlationId = null, replyTo = null, persistent = true, type = null, priority = 4, groupID = null, groupSequence = 0, targetConsumerId = null, compressed = false, userID = null, content = null, marshalledProperties = null, dataStructure = null, redeliveryCounter = 0, size = 0, properties = null, readOnlyProperties = false, readOnlyBody = false, droppable = false, jmsXGroupFirstForConsumer = false}
INFO  com.maxis.mxmove.core.SelectedDataJmsWriter - Committed 1 stuff to redo log and JMS queue

*** We received the last message, not the first.  We show two enqueues, and one dequeue.. ***
DEBUG com.maxis.mxmove.core.SelectedDataJmsReader - Received: ActiveMQObjectMessage {commandId = 7, responseRequired = true, messageId = ID:zip-56502-1457640572818-4:2:2:1:2, originalDestination = null, originalTransactionId = null, producerId = ID:zip-56502-1457640572818-4:2:2:1, destination = queue://Stuff via SQL.402, transactionId = null, expiration = 0, timestamp = 1457640610375, arrival = 0, brokerInTime = 1457640610375, brokerOutTime = 1457640610376, correlationId = null, replyTo = null, persistent = true, type = null, priority = 4, groupID = null, groupSequence = 0, targetConsumerId = null, compressed = false, userID = null, content = null, marshalledProperties = null, dataStructure = null, redeliveryCounter = 0, size = 1024, properties = null, readOnlyProperties = true, readOnlyBody = true, droppable = false, jmsXGroupFirstForConsumer = false}
INFO  com.maxis.mxmove.core.SelectedDataJmsReader - executed read, found end-of-stream marker, returning null
DEBUG org.apache.activemq.broker.region.Queue - queue://Stuff via SQL.402, subscriptions=2, memory=0%, size=1, pending=0 toPageIn: 0, Inflight: 1, pagedInMessages.size 1, pagedInPendingDispatch.size 0, enqueueCount: 2, dequeueCount: 1, memUsage:1107
pojo-guy
  • 966
  • 1
  • 12
  • 39
  • Could you please provide a small working example which demonstrates the behavior. – SubOptimal Mar 10 '16 at 07:53
  • I stripped out a small working example, but the behavior is not replicated. – pojo-guy Mar 10 '16 at 20:00
  • I enabled debug logging in the activemq Queue and updated the log snip in the original post. – pojo-guy Mar 10 '16 at 20:04
  • Usually, if I see lost messages that don't have any timeout, there is some other consumer stealing them. – Matej Mar 10 '16 at 20:24
  • I would normally agree. The AMQ logs clearly show that there was two enqueue's but only one dequeue. The ID of the dequeued message was the id ofthe second message enqueued. I already checked, and there is only one point at which we receive the data. The queue is not published outside of the JVM for this degenerate test case. – pojo-guy Mar 10 '16 at 21:28
  • @pojo-guy `but the behavior is not replicated` then the issue is clearly in the code which we don't know. ;-) Could you show how you create/configure the queues/sender/receiver? Maybe this could provide more information to us. – SubOptimal Mar 11 '16 at 06:44
  • @SubOptimal - I agree, the problem is something I am missing. – pojo-guy Mar 11 '16 at 15:25

1 Answers1

5

In the Receiver Setup code, note that the beforeStep() method is annotated with @BeforeStep. I think this means that the receiver is being set up twice, and probably with a prefetch optimization. This is validated because the log shows TWO subscriptions. Not being a heavy JMS user, I was under the mistaken impression that one was for the receiver but the other was for the sender.

@Override
@BeforeStep
public void beforeStep(StepExecution stepExecution) {
    this.stepExecution = stepExecution;
    this.setJobExecution(stepExecution.getJobExecution());

After removing the @BeforeStep annotation, the log shows only one subscription

DEBUG org.apache.activemq.broker.region.Queue - queue://Workorders via SQL.408, subscriptions=1, memory=0%, size=1, pending=0 toPageIn: 0, Inflight: 1, pagedInMessages.size 1, pagedInPendingDispatch.size 0, enqueueCount: 1370, dequeueCount: 1369, memUsage:1024

The next time someone tells me how "clean" code is when you employ injection, I may consider applications of Martial Arts Exchange

Community
  • 1
  • 1
pojo-guy
  • 966
  • 1
  • 12
  • 39