springamazon-web-servicesamazon-sqsaspectsqslistener

Spring SQS Message Handler - add custom message attributes to existing message before sending it to Dead-Letter-Queue


Currently, the messages on source queue are sent to dead-letter-queue on every exception. My goal is to add custom attributes to the failed message so that engineers have more information about failure when they monitor the dead-letter-queue.

When I tried to add attributes to existing message, I receive an java.lang.UnsupportedOperationException exception.

Here is the aspect code where I add message attributes to existing message. I am using custom aspect which is triggered before sending the message with AmazonSQSClient.

@Before(value = "execution(* com.amazonaws.services.sqs.AmazonSQS*Client.sendMessage*(com.amazonaws.services.sqs.model.SendMessageRequest,..)) && args(request,..)",
        argNames = "request")
public void before(SendMessageRequest request) {
   
    Map<String, MessageAttributeValue> messageAttributes = request.getMessageAttributes();
    if (messageAttributes == null) return;
    messageAttributes.put("MoveToDlqFlag", createMessageAttribute("true"));
}

This is the code where exception happens.

@SqsListener(value = {"${sqs.queue.source-queue}"}, deletionPolicy = ON_SUCCESS)
public void handleMessageReceived(String rawMessage, @Header("SenderId") String senderId, @Headers Map<String, Object> header) {
    var orderMessageWrapper = messageWrapperUtil.create(rawMessage, Order.class);
    var order = orderMessageWrapper.getMessage();
    var receiveCount = (Integer) header.get("ApproximateReceiveCount");

    ...
}

Is there a way to add message attributes to existing message before sending to dead-letter-queue? Maybe spring provides a configuration where it is possible.


Solution

  • If messageAttributes map throws java.lang.UnsupportedOperationException, then maybe you could try to create a new mutable map, which is a copy of immutable map:

    Map<String, MessageAttributeValue> messageAttributes = new HashMap<>(request.getMessageAttributes());
    

    and then you can use setMessageAttributes() of SendMessageRequest

    So I hope that this solution would work (unless setMessageAttributes doesn't throw UnsupportedOperationException too)

    Map<String, MessageAttributeValue> messageAttributes = request.getMessageAttributes() == null ? new HashMap<>() : new HashMap<>(request.getMessageAttributes());   
    messageAttributes.put("MoveToDlqFlag", createMessageAttribute("true"));
    request.setMessageAttributes(messageAttributes);