简体   繁体   中英

basicAck does not remove message from broker - RabbitMQ

I'm doing following flow in my application:

  1. get 1 message from broker(manual acknowledge)

  2. do some processing

  3. start transaction on database and broker

  4. insert some records in database and publish some messages on broker(different queue)

  5. commit database and broker

  6. ack message that you got from broker in step 1.

All operation on broker is done via a single channel. here is the preparation code:

Connection brokerConnection = factory.newConnection();              
Channel channel = brokerConnection.createChannel();
channel.basicQos(1);
QueueingConsumer consumer = new QueueingConsumer(channel);
channel.basicConsume("receive-queue", false, consumer);

Following is my code. I have removed try , catch parts to make it clear. I log all exceptions to file. Step 1:

QueueingConsumer.Delivery delivery = consumer.nextDelivery();
Request request = (Request) SerializationUtils.deserialize(delivery.getBody());

Step 2, 3, 4, 5:

dbConnection.setAutoCommit(false);
channel.txSelect();

stmt = dbConnection.prepareStatement(query);
/* set paramteres */
stmt.executeUpdate();
channel.basicPublish(/* exchange name */, "KEY", MessageProperties.PERSISTENT_BASIC, /* result */ result);

dbConnection.commit();
channel.txCommit();
dbConnection.setAutoCommit(true);

Step 6:

channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false);

After one iteration I can see records in database and broker(means it is working fine until step 5). The problem is the message on receive queue is not removed after step 6 and management plug-in shows one un-acked message. Also I don't see any exception in log file. Can anyone help?

[UPDATE1]

Now I create one channel for publishing and another channel for receiving. This is working now. So how to use a single channel for receiving and publishing(with transactions)? I have used a single channel for receiving and publishing before but that was without transactions.

[UPDATE2]

I moved step 6 inside transaction and it is working now.

dbConnection.setAutoCommit(false);
channel.txSelect();

stmt = dbConnection.prepareStatement(query);
/* set paramteres */
stmt.executeUpdate();
channel.basicPublish(/* exchange name */, "KEY", MessageProperties.PERSISTENT_BASIC, /* result */ result);

channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false); 

dbConnection.commit();
channel.txCommit();
dbConnection.setAutoCommit(true);

I'm a bit confused. I just want the publish section to be inside transaction.

You've put the channel in transactional mode - and acks are transactional things. So you either need to consume and ack on a separate non-transactional channel, or else just accept that your ack needs to come before the tx.commit.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM