Skip to content

Too long closeMessage in StrictExceptionHandler.handleConsumerException #344

@ghost

Description

In autogenerated com.rabbitmq.client.impl.AMQImpl.Close class, method writeArgumentsTo uses writeShortstr to write replyText:

            public void writeArgumentsTo(MethodArgumentWriter writer)
                throws IOException
            {
                writer.writeShort(this.replyCode);
                writer.writeShortstr(this.replyText);
                writer.writeShort(this.classId);
                writer.writeShort(this.methodId);
            }

Method writeShortstr throws IllegalArgumentException when argument has length more than 255 bytes.

StrictExceptionHandler.handleConsumerException form closeMessage as "Consumer " + consumer + " (" + consumerTag + ")" + " method " + methodName + " for channel " + channel. When consumer class name is enough long, uncatched exceptions in hadleDelivery method will trigger close of channel, but close message won`t be sent to server and server will continue to send messages into the closed on client side channel.

Code to show the problem (slightly modified code from tutorial).
Consumer

import com.rabbitmq.client.*;

import java.io.IOException;

public class VeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongClassName {

    private final static String QUEUE_NAME = "hello";

    public static void main(String[] argv) throws Exception {
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("localhost");
        Connection connection = factory.newConnection();
        final Channel channel = connection.createChannel();

        channel.queueDeclare(QUEUE_NAME, false, false, false, null);
        System.out.println(" [*] Waiting for messages. To exit press CTRL+C");

        Consumer consumer = new DefaultConsumer(channel) {
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body)
                    throws IOException {
                String message = new String(body, "UTF-8");
                System.out.println(" [x] Received '" + message + "'");
                channel.basicReject(envelope.getDeliveryTag(), true);
                throw new RuntimeException("Some exception");
            }
        };
        channel.basicConsume(QUEUE_NAME, false, consumer);
    }
}

Producer

import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;

public class Send {

    private final static String QUEUE_NAME = "hello";

    public static void main(String[] argv) throws Exception {
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("localhost");
        Connection connection = factory.newConnection();
        Channel channel = connection.createChannel();

        channel.queueDeclare(QUEUE_NAME, false, false, false, null);

        String message = "Hello World!";
        channel.basicPublish("", QUEUE_NAME, null, message.getBytes("UTF-8"));
        System.out.println(" [x] Sent '" + message + "'");

        channel.close();
        connection.close();
    }
}

After sending first message it is expected that channel is closed and queue contain one ready message. But channel is not closed and message in queue is in unacked state. Because server does not know that channel is closed, it continue to send new messages to this channel.

This example is not synthetical - i faced this problem in prouction with 90 symbols length full qualified class name (42 symbols for package name, 26 symbols class name and 20 symbols inner class name).

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions