Spring AMQP MessageProperties:all headers were removed during deadlettering - java

I have got a question about Spring AMQP Message:
During processing I was able to update headers of message properties in String AMQP Message with some specific values.
After DeadLettering of this message, all specific headers were disappeared/removed.
Is this behaviour correct ?
Looking forward to your response.
Regards, Anton.
spring-rabbit.version: 1.3.5.RELEASE
spring.version: 4.1.1.RELEASE

The broker knows nothing about your client-side consumer changes; the original message (with its orignal headers) is dead-lettered by the broker (with an x-death header added to indicate the reason - rejection, expiry etc).
In order to do what you want, you need to publish your modified message yourself rather than using dead-lettering.
See the RepublishMessageRecoverer for an example using Spring retry. You can make a custom recover, or simply catch the exception in your listener to republish.

Related

Spring MVC like processing of AMQP messages

What I want to do is process AMQP messages in a very similar way the Http Requests are processed using spring-webmvc annotations such as #RequestMapping, #RequestParam etc. But, instead of the Http Request my source object will be an AMQP message. The AMQP message request will have two headers, for example -
method="POST"
url="/api/myobjects/{someParam}"
and the payload will contain data in json format.
If you have noticed, this is nothing but HTTP REST api mapped to AMQP message.
I want to be able to write a controller like handler, for example -
#Controller
public class MyObjectHandler {
#RequestMapping(value="/api/myobjects/{someParam}", method="POST")
public MyObject createMyObject(#Payload MyObject myObj, #PathParam String someParam) {
//... some processing
return myObj;
}
// ...more handlers
}
I have looked at spring-amqp/rabbitmq annotations and also spring integration annotations. They are close to what I want, but would not allow routing to handler methods based on header parameters, especially the REST url.
I don't expect that a readymade solution would be available for this. Just want to make sure I choose the best possible option. Some of the options I think are (in order of precedence)
If the spring-webmvc annotation processing mechanism is extensible, just extend it to use AMQP message as source instead of Http Request
Modify the spring-webmvc annotation processing mechanism to take the AMQP message as input instead of Http Request
Write your own solution with custom annotaions and their processors, which I think is a very involving task
Or any other possible approach than above?
Any guidance/direction is appreciated.
I think the starting point is likely AbstractMethodMessageHandler in spring-messaging.
There's currently a SimpAnnotationMethodMessageHandler implementation for websockets which invokes #Controllers.
You could use a #RabbisListener method that has a Message<?> parameter (Spring AMQP will convert the underlying Rabbit message to a spring-messaging message, including the headers). Then, invoke the message handler to route to the appropriate controller method.
If you come up with a robust implementation, please consider contributing it.

Different dead-letter-queues in Spring Amqp + RabbitMQ based on exception

Given a basic MessageListener implementation which consumes messages from a RabbitMQ queue, how can I send the message to different dead-letter-queues based on the type of exceptions that could be thrown while processing it?
The queue were the messages are originally published has the x-dead-letter-exchange and x-dead-letter-routing-key set on it, but this is not enough in my case.
In case it matters, my application is using Spring 4 and Spring Amqp.
As far as I understand RabbitMQ documentation and Spring AMQP, it is not possible to send a message to different DLQs based on conditions from inside the code. The reason I say this is that my understanding from debugging the code is that when a message has to be send to a DLQ, the code doesn't specify the exchange or the routing key and RabbitMQ uses the ones defined when the message was published.
So, the only solution I found is to implement something like this:
try {
try_to_do_useful_stuff(message);
} catch (BusinessException e) {
resend_the_message_to_business_dlq(message);
}
This way, if a business exception is thrown, then the message is manually send to the business DLQ. Of course, some details get lost, like originating queue, but this is not an issue if they're not used.
When a non-business exception is thrown then the standard path is followed: retry (if configured) and then route to the defined DLQ.

How to change Failed Message of Messaging Exception in Spring

I am using spring integration based Component. That components receives some XML and enriched that XML with some more content.
However, if an exception occurs , then i want to sent the received input XML as the failed message, however in current scenario, it will hold the partially enriched XML as there failed Message.
Is there any way through which I can change the failed message of the Exception , which in turn is wrapped by the Messaging Exception.
As it is so specific case, we need to see your configuration and especially where is an error-channel and how you enrich XML.
However, keep in mind, that Message is immutable object and each interaction with it provides a new Message. But the payload is out of scope of the messsaging and it might not be immutable. And if change of some property of your payload and then you get some exception, you end up in the ErrorMessage with inbound message (failed), but payload might change its state.
Looks like it is your case.
You should think about some payload-cloning variant before you start to enrich it.
Here are some advices on the matter: https://jira.springsource.org/browse/INT-2979

Spring integration application and cache

Have spring integration application with inbound http gateway and outbound http gateway, between those i want to have cache, to avoid unnessesary requests. The only solution i have is to add interceptor with cache and router after it that routes cahced results back to reply channel, and non cached to outbound, but this solution seems tricky and ugly to me.
Interceptor with cache also works good when inbound gateway has same channel for request and reply, (when returns new message with same headers but different payload, its considered as reply) but its not the case I can use.
Any better ideas for this?
More elegant solution can be achieved with <request-handler-advice-chain>
and Spring Cache Advice.
So, your solution may be like this:
<int-http:outbound-gateway>
<int-http:request-handler-advice-chain>
<cache:advice>
<cache:caching cache="foo">
<cache:cacheable method="handle*Message" key="#a0.payload"/>
</cache:caching>
</cache:advice>
</int-http:request-handler-advice-chain>
</int-http:outbound-gateway>
Where handle*Message is handleRequestMessage method of HttpRequestExecutingMessageHandler. And exactly for this method Spring Integration applies his Advices (e.g. RequestHandlerRetryAdvice).
Here you should configure a cacheManager bean, choose cache name and determine a key for cache entry. In sample above #a0 is a Message object from handleRequestMessage arguments. So, you can specify any SpEL expression against message properties (payload and headers).
And the result of handleRequestMessage will be stored in the cache.
And when you provide the same parameters for HTTP reqeust, the result will be returned just from cache.

Spring Integration Gateway with no arguments

On my gateway, I have a method
#Gateway
String commsTest();
The idea is that I can call commsTest from the bean and use spring integration to wire it up to the service activator that will check comms.
When I do that I get a receive is not supported, because no pollable reply channel has been configured error. I realise that this is because a method with no params means "I am trying to poll a message from the channel"
This is a two part question.
What does it mean to poll a message from the channel.
How can I get the functionality I want.
Spring Integration currently has no concept of a message without a payload. By default, a gateway method with no arguments implies you want to receive data (rather than sending data or sending and receiving data).
You can change that default behavior, as described in the reference documentation.

Categories