How do I apply a delay to messages on a FIFO SQS? - spring-cloud-aws

Using 'io.awspring.cloud:spring-cloud-starter-aws-messaging' how can we apply a per-queue delay to the messages in the queue?
When I do the following...
sqsTemplate.convertAndSend( "myqueue.fifo", myObject, Map.of(SQS_GROUP_ID_HEADER, id, SQS_DEDUPLICATION_ID_HEADER, UUID.randomUUID().toString(), SQS_DELAY_HEADER, 1 )
I see...
org.springframework.messaging.MessageDeliveryException: Value 1 for parameter DelaySeconds is invalid. Reason: The request include parameter that is not valid for this queue type.
https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-delay-queues.html

The delay is set on the FIFO itself not via the service consuming it.

Related

Handling PENDING messages from Redis Stream with Spring Data Redis

When using StreamMessageListenerContainer a subscription for a consumer group can be created by calling:
receive(consumer, readOffset, streamListener)
Is there a way to configure the container/subscription so that it will always attempt to re-process any PENDING messages before moving on to polling for new messages?
The goal would be to keep retrying any message that wasn't acknowledged until it succeeds, to ensure that the stream of events is always processed in exactly the order it was produced.
My understanding is if we specify the readOffset as '>' then on every poll it will use '>' and it will never see any messages from the PENDING list.
If we provide a specific message id, then it can see messages from the PENDING list, but the way the subscription updates the lastMessageId is like this:
pollState.updateReadOffset(raw.getId().getValue());
V record = convertRecord(raw);
listener.onMessage(record);
So even if the listener throws an exception, or just doesn't acknowledge the message id, the lastMessageId in pollState is still updated to this message id and won't be seen again on the next poll.

Spring AMQP- How does i retry/re-queue message from DLX queue to original queue?

i am trying to implement below scenario in my application
Exachange e1 -> Queue q1
DLX exchange e2 -> Queue q2
Also i have mentioned DLE and DLK in queue-q1 then message moving to queue-q2 on rejection/failure/timeout.
But how does i resend/retry message from queue-q2 to original queue-q1?
You can do that manually in your application after some analyze and filtering logic. Or you can make some TTL on that queue-q2 to let not consumed messages to be expired. And you also need to specify in this queue a x-dead-letter-exchange as a name for the Exachange e1 for desired recycling.
See more info yin this article:
Create the dead letter exchange, which is just a normal exchange with a special name
Create a retry_message queue and have all messages published to the dead letter exchange route here
When you setup the retry_message queue, be sure to default the following parameter values of the queue
x-message-ttl: 30000 – This will set a ttl on any message published to the queue. When the ttl expires, the message will be republished to the exchange specified in the x-dead-letter-exchange parameter.
x-dead-letter-exchange: original_exchange_name – This is where the message will get republished to once the message ttl expires. We normally want this be the name of the exchange where the message was originally published.

Remove message from rabbit MQ after limited attempts of requeing

I put records from a file into rabbit mq,read records from queue and call a service.For rejected records,I am sending a negative acknowledgemnt and requeuing with channel.basicNack method.But requirement is that we need to make only some 3 attempts of service call.After that we have to remove the message from the queue rather keep on calling the service again and again.
On the last attempt, set the requeue argument in basicNack to false.

How to make rabbitmq to refuses messages when a queue is full?

I have a http server which receives some messages and must reply 200 when a message is successfully stored in a queue and 500 is the message is not added to the queue.
I would like rabbitmq to refuse my messages when the queue reach a size limit.
How can I do it?
actually you can't configure RabbitMq is such a way. but you may programatically check queue size like:
`DeclareOk queueOkStatus = channel.queueDeclare(queueOutputName, true, false, false, null);
if(queueOkStatus.getMessageCount()==0){//your logic here}`
but be careful, because this method returns number of non-acked messages in queue.
If you want to be aware of this , you can check Q count before inserting. It sends request on the same channel. Asserting Q returns messageCount which is Number of 'Ready' Messages. Note : This does not include the messages in unAcknowledged state.
If you do not wish to be aware of the Q length, then as specified in 1st comment of the question:
x-max-length :
How many (ready) messages a queue can contain before it starts to drop them from its head.
(Sets the "x-max-length" argument.)

JMS message priority not working on Message

I need to set message priority so that High priority messages are consumed before Low priority messages by Receivers.
First I tried with message.setJMSPriority() method to set the priority but it was not working in HornetQ and ActiveMQ so finally I set the priority of the Message Producer using setPriority() method and it works fine now.
Why isn't Messsge.setJMSPriority() working in any of the JMS vendor implementations and why do we need to set the priority of the Producer not the message itself to set the priority of the message? What is the use of Messsge.setJMSPriority() method then?
Any suggestion or comment is appreciated.
To answer this question all you need to do is read the API docs for the setJMSPriority method and it tells you why. Here's the relevant text.
Sets the priority level for this message.
JMS providers set this field when a message is sent. This method can be used to change the value for a message that has been received.
The JMS Provider (ActiveMQ, HornetMQ, etc) set the priority in the producer on send to either the default value of 4, or to whatever value you've set the producer to use, so setting the value before send on the message itself won't have any effect.
The following will not work:
msg.setJMSPriority(9); // Not working!
In this code, the message priority is set to 9, indicating this is a high-priority message.
However, when the message is sent, the message will have a priority of 4 (normal
priority). The reason? Like the message expiration, the JMS provider will look at the
message priority property on the sender, or on the send(..) invocation, and then invoke the setJMSPriority on the message method prior
to placing the message on the queue. Since the default message priority is 4 (normal
priority), the message priority will not be set to a high priority message, as the developer had originally intended.
Like the message expiration, there are two ways of setting the message priority: you
can invoke the setPriority() method on the MessageProducer (QueueSender or Topic
Publisher) or set the message priority when sending the message:
//set the default message priority for all messages to 9 (high)
QueueSender qSender = qSession.createSender(requestQ);
qSender.setPriority(9);
qSender.send(msg1);
//this message is low priority
qSender.send(msg2, DeliveryMode.PERSISTENT, 1, 30000);
In this example, msg1 will be sent with a priority of 9 (high priority), whereas msg2 will
be sent with a priority of 1 (low priority).
This is a JMS Specification requirement.
You should change the priority on the Message Producer.
You can read JmsTemplate http://static.springsource.org/spring/docs/3.0.6.RELEASE/spring-framework-reference/html/jms.html
Some JMS providers allow the setting of default QOS values administratively through the configuration of the ConnectionFactory.
Check isExplicitQosEnabled property.