1
votes

We are using Azure Service Bus Queues for exchanging messages between different systems. We would like to move the invalid messages to Dead Letter Queue using Java code.

I am able to move the messages to the Main queue, but not to dead letter queue. I tried to give the queue name as "BasicQueue/$deadletterqueue", but I was getting the error.

1
Could you please post some patch of your code and error as wellKeren Caelen

1 Answers

5
votes

There are many reasons why a message may be automatically moved to the dead letter queue by the Azure Service bus runtime, such as:

  • The max delivery count is exceeded (Default is 10 when enabled);
  • The Message Time to Time (TTL) is exceeded;
  • Etc.;

Find more details at https://docs.microsoft.com/en-us/azure/service-bus-messaging/service-bus-dead-letter-queues, including a full list of reasons why messages are moved to the dead letter queue.

In addition, it is possible for the application to move messages to the dead letter queue. Find a sample Java 8 Console Application code and the pom.xml file further below.

Please note The following properties are automatically filled up by the Azure Service Bus runtime when moving messages to the dead letter queue, it is a good idea to also provides those when the application it performing the same action:

DeadLetterReason

DeadLetterErrorDescription

-- Java Version --

java version "1.8.0_162"
Java(TM) SE Runtime Environment (build 1.8.0_162-b12)
Java HotSpot(TM) 64-Bit Server VM (build 25.162-b12, mixed mode)

--- Azure Service Bus Dependency for pom.xml ---

<dependencies>
    <!-- https://mvnrepository.com/artifact/com.microsoft.azure/azure-servicebus -->
    <dependency>
        <groupId>com.microsoft.azure</groupId>
        <artifactId>azure-servicebus</artifactId>
        <version>2.0.0-preview1</version>
    </dependency>
</dependencies>

-- Java 8 Console Application --

import java.time.Duration;
import java.util.Scanner;
import com.microsoft.azure.servicebus.MessageHandlerOptions;
import com.microsoft.azure.servicebus.QueueClient;
import com.microsoft.azure.servicebus.ReceiveMode;
import com.microsoft.azure.servicebus.primitives.ConnectionStringBuilder;
import com.microsoft.azure.servicebus.primitives.ServiceBusException;

public class Main {
    public static void main(String[] args)
    {
        final String CONNECTION_STRING = "{Azure Service Bus Connection String}";
        final String QUEUE_NAME = "{Azure Service Bus Queue Name}";

        try {
            moveMessageToDlq(CONNECTION_STRING, QUEUE_NAME);
        }catch (Exception ex) {
            System.out.println(String.format("An exception occurred. Details: %s.", ex.toString()));
        }
    }

    private static void moveMessageToDlq(String connectionString, String queueName)
            throws ServiceBusException, InterruptedException {

        ConnectionStringBuilder connectionStringBuilder = new ConnectionStringBuilder(connectionString, queueName);
        QueueClient queueClient = new QueueClient(connectionStringBuilder, ReceiveMode.PEEKLOCK);

        MessageHandler messageHandler = new MessageHandler(queueClient);

        MessageHandlerOptions messageHandlerOptions = new MessageHandlerOptions(
                1,
                false,
                Duration.ofMinutes(1));

        queueClient.registerMessageHandler(messageHandler, messageHandlerOptions);

        final String QUIT_COMMAND_NAME = "quit";
        Scanner scanner = new Scanner(System.in);

        while (true) {
            System.out.println(String.format("Enter '%s' and press <ENTER> to exit...", QUIT_COMMAND_NAME));
            String input = scanner.nextLine();

            if (input.equalsIgnoreCase(QUIT_COMMAND_NAME)){
                System.out.println("Exiting...");
                break;
            }
        }

        scanner.close();

        queueClient.close();
    }
}

--- Message Handler ---

import java.util.concurrent.CompletableFuture;
import com.microsoft.azure.servicebus.ExceptionPhase;
import com.microsoft.azure.servicebus.IMessage;
import com.microsoft.azure.servicebus.IMessageHandler;
import com.microsoft.azure.servicebus.IQueueClient;

public class MessageHandler implements IMessageHandler {
    private final IQueueClient _client;

    public MessageHandler(IQueueClient client) {
        if (client == null){
            throw new IllegalArgumentException("Queue client cannot be null.");
        }
        _client = client;
    }

    @Override
    public CompletableFuture<Void> onMessageAsync(IMessage message) {
        System.out.println(String.format("Received message id '%s' (DeliveryCount=%d).",
                message.getMessageId(),
                message.getDeliveryCount()));

        if (message.getLabel().equalsIgnoreCase("dlq")){ // Send message to DLQ if label id dlq
            System.out.println("Sending message to the dead letter queue...");

            return _client.deadLetterAsync(
                    message.getLockToken(),
                    "InvalidMessage", // DeadLetterReason
                    "Message invalid due to..."); // DeadLetterErrorDescription
        }
        else { // Otherwise, complete message
            System.out.println("Completing message...");

            return _client.completeAsync(message.getLockToken());
        }
    }

    @Override
    public void notifyException(Throwable throwable, ExceptionPhase exceptionPhase) {
        System.out.println("An exception occurred. Details: " + exceptionPhase + "-" + throwable.getMessage());
    }
}

GitHub Azure Service Bus Java Samples: https://github.com/Azure/azure-service-bus-java/tree/e3d163eac92213d34dce059f3353d2c819d31fbf.