In jms (v1.0) subscriber client ack mode, message.acknowledge() is the only way to send an ack back to server(broker) side. The actual behaviour is if client ack to message3 then message sender(broker) client acks to all messages up to message3[1].
i.e
msg1, msg2, msg3 is delivered to the client in order.
Client process messages ACK for every message, msg1, msg2 and msg3. >> OK
Knowing the actual behaviour client acks as batches(batch size=3), so asks to msg3 > OK (all messages upto msg3 get acked)
In scenario 1 and 2, broker get notified that client ACK to all 3 messages delivered. And client also actually process all 3 and ACK back.
Consider following scenario :
a. msg1 comes to client.
b. failed to process msg1. So avoid ack back. (msg1 never processed or acked from client side)
c. msg2 comes and successfully processed. And ack to msg2.
Therefore in the above scenario client ack does not guarantee the delivery of msg1.
Please explain is there a workaround to guaranteed delivery when batch process with client ack through JMS 1.0 spec.
[1] http://docs.oracle.com/javaee/7/api/javax/jms/Message.html#acknowledge
According to the spec:
By invoking acknowledge on a consumed message, a client acknowledges all messages consumed by the session that the message was delivered to.
So, the deal is to not acknowledge any more messages in a session where a message has failed.
Instead, if you detect a failure, you could either:
Tear down the session (or even Connection).
Invoke recover on your Session. That will restart message delivery with the oldest unacknowledged message.
Related
I am using Amazon SQS with Amazon SQS-JMS java library with Java EE 7. What I want to achieve is after receiving a message, depending on business logic of the application either confirm (consume) the message or resend it to the queue again and after 3 failed retries move it to DLQ.
I though about using CLIENT_Acknowledge mode in JMS and only acknowledging the messages that were successfully processed, but this is from their official documentation:
In this mode, when a message is acknowledged, all messages received before this message are implicitly acknowledged as well. For example, if 10 messages are received, and only the 10th message is acknowledged (in the order the messages are received), then all of the previous nine messages are also acknowledged.
This example also seems to confirm this: http://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/code-examples.html#example-synchronous-receiver-client-acknowledge-mode.
For me this is kind of a strange behavior and opposite what I would expect from a client_acknowledge. Is there a more elegant solution here than just manually sending message throughout the code to main SQS queue or DLQ depending on process status?
You can use:
UNORDERED_ACKNOWLEDGE
SQSSession.UNORDERED_ACKNOWLEDGE
Which comes from 'com.amazon.sqs.javamessaging;' and as it states in the documentation it is a variation of Client_Acknowledge which only acknowledges the message for which it is called.
/**
* Non standard acknowledge mode. This is a variation of CLIENT_ACKNOWLEDGE
* where Clients need to remember to call acknowledge on message. Difference
* is that calling acknowledge on a message only acknowledge the message
* being called.
*/
dependency example:
"com.amazonaws:amazon-sqs-java-messaging-lib:1.0.3"
To handle this case you can use RedrivePolicy attribute for the DLQ that you created. Solution for this case can be:
Create a 2 sqs Qs say my_q and my_q_dl (latter one is for DLQ)
Set DLQ my_q_dl as the DLQ of my_q by using RedrivePolicy.
Here, care should be taken to specify deadLetterTargetArn and maxReceiveCount. This maxReceiveCount is the number of times you want to process any message without acknowledging before sending it to the DLQ. If you set maxReceiveCount=3 then, the msg will remain in my_q up to 3rd pull by the consumer with no ack.
2 cases here:
Normal case: msg gets deleted as soon as ack is received.
If no ack (msg delete) for that msg upto third time then the msg gets deleted from my_q and pushed to
my_q_dl itself.
*RedrivePolicy - The string that includes the parameters for the deadletter queue functionality of the source queue.
deadLetterTargetArn - The Amazon Resource Name (ARN) of the dead-letter queue to which Amazon SQS moves messages after the value
of maxReceiveCount is exceeded.
maxReceiveCount - The number of times a message is delivered to the source queue before being moved to the dead-letter queue.
Note
The dead-letter queue of a FIFO queue must also be a FIFO queue. Similarly, the dead-letter queue of a standard queue must also be a
standard queue.*
I have a rabbitmq queue and two spring cloud spring consumers.
I want that each consumers process messages in order.
I thought that when consumer1 send ack, consumer2 receive second message,
so I expected message1, message2 is processed in order in each consumers.
-------------------- time pass ------------------------>
consumer1: message1 message3
consumer2: message2 message4
But it wasn't. consumer1, consumer2 receive message1, message2, and process simultaneously.
-------------------- time pass ------------------------>
consumer1: message1 message3
consumer2: message2 message4
Is there a way for spring cloud stream to consume messages exclusively?
RabbitMQ (AMQP) doesn't support that; each consumer gets prefetch messages.
It does support exclusive consumers, but it means consumer1 would get all the messages and consumer2 would only get messages if consumer1 dies.
However, Spring Cloud Stream doesn't currently provide a property to set that option.
you would have to model your queues in a different way. E.g. by having an "incoming" queue which has exactly one consumer-coordinator. This consumer would relay messages to the "work" queue where consumer1+2 are both waiting and pick up work in a round robin way.
They would then signal completion to the coordinator on a third queue which would cause it to resume relaying a single message to the work queue.
I have SMPP server, use CloudHoper.
When I get a message I should return a delivery report.
Please, tell me, how I can do it?
At this moment I return SubmitSmResp...
Of course you still need to answer the SubmitSm PDU with a SubmitSmResp PDU as you do now.
A delivery report is a "special" DeliverSm PDU which is generated in your SMPP server and sent additionally to your client. See SMPP 3.4 Appendix B how it is formatted (https://github.com/twitter/cloudhopper-smpp/blob/master/src/etc/SMPP_v3_4_Issue1_2.pdf). You also need to set esmClass of the DeliverSm PDU to 0x04 to indicate it's a delivery report.
If your client is using a transceiver bind, you can use the same session to send the DeliverSm PDU to, otherwise you need use the clients receiver session. If no active session is available you need to queue the DeliverSm PDU.
The main question is when to send the delivery report. First of all, you may send only a delivery report, if the client requested one, by setting the 4th bit of the SubmitSm esmClass.
Although, if your client is using a transceiver connection, don't send it directly in the firePduRequestReceived handler. The client may receive it before it receives the SubmitSmResp. Additionally this delivery report would not have more value than the SubmitSmResp itself.
So there are three cases when you may generate this delivery report and queue it until you have a proper session from your client to send it to:
1) When you receive some external event indicating that the former SubmitSm was actually processed (e.g. delivered) by it's destination.
2) When you are able to forward the SubmitSm to the next processing unit.
3) When you detect any error or the SubmtSm expired
Create a DELIVER_SM for that message and send that to the client.
I have a Queue and Topic with 2 messages in Activemq.If I restart Activemq.I am losing messages and also Topic.
Even If I restart Activemq,I don't want to lose any messages from any Topicand Queue.Is it possible.
I am using Activemq 5.8.0.
A producer produces the message and send it to the Topic, which ever
consumer is running at that point of time, will receive the message.
If you want consumer which is not up now, but might be running in
future to get this message, you will have to tell the Broker to
persist the message and store the information that this perticular
consumer has not received the message.
If you have working code with-out durable subscriber, you will have to do the following changes.
In the consumer,
1. set the clinetId. Because Topic should know which consumer is yet to receive the message. Or has received the message.
Connection.setClientID(String)
2. Should be creating a durable subscriber for your topic
Connection.createDurableSubscriber()
3. Add your listener to this subscriber.
subscriber.setMessageListener(yourlistener)
4. Once you receive the message, you will have to acknowledge it
This link shows how it is done: But its in c# i guess.
http://myadventuresincoding.wordpress.com/2011/08/16/jms-how-to-setup-a-durablesubscriber-with-a-messagelistener-using-activemq/
Read these links for more info :
http://activemq.apache.org/how-do-durable-queues-and-topics-work.html
http://activemq.apache.org/why-do-i-not-receive-messages-on-my-durable-topic-subscription.html
http://activemq.apache.org/manage-durable-subscribers.html
I have a situation in which the I'm reading messages from a queue using a message consumer (javax.jms.MessageConsumer) .
The session used is using AUTO_ACKNOWLEDGE mode.
From what I've read so far on AUTO_ACK mode:
In auto acknowledgement if the consumer's onMessage() method completes without error the message is considered received and processed successfully, it'll be then removed from the JMS server.
My question is when is the message considered to be ACK by the JMS producer considering I`m not using an MDB that has an onMessage() method but reading the messages by using the message consumer described earlier.
Is the message ACK'ed once I successfully read it using the messageConsumer ?
What will happen if further down the logic-chain a method that uses the respective message will throw an error ? Will the message already be ACK'ed by that time ?
The Javadoc for the AUTO_ACKNOWLEDGE constant says this:
With this acknowledgment mode, the session automatically acknowledges
a client's receipt of a message either when the session has
successfully returned from a call to receive or when the message
listener the session has called to process the message successfully
returns.
I suspect you are calling receive on the MessageConsumer (although you don't explicitly state that) so if you set AUTO_ACKNOWLEDGE it is acknowledged by the time receive returns.
Of course if you have a transacted session then the acknowledge mode is ignored and the message isn't considered received until the session is committed.