MqttClient publisher = new MqttClient(MQTT_URL,clientId+configId);
MqttConnectOptions options = new MqttConnectOptions();
options.setAutomaticReconnect(true);
options.setCleanSession(true);
options.setConnectionTimeout(10);
publisher.connect(options);
MqttMessage msg = new MqttMessage(payload);
msg.setQos(0);
msg.setRetained(true);
publisher.publish(topic,msg);
I'm using the PAHO MQTT java library. In the code above, once the message is published, is there any callback available using which I can verify if the message was delivered to the broker?
From the Paho Javadoc:
deliveryComplete
void deliveryComplete(IMqttDeliveryToken token)
Called when delivery for a message has been completed, and all acknowledgments have been received. For QoS 0 messages it is called
once the message has been handed to the network for delivery. For QoS
1 it is called when PUBACK is received and for QoS 2 when PUBCOMP is
received. The token will be the same token as that returned when the
message was published.
Parameters:
token - the delivery token associated with the message.
You will need to implement the MQTTCallback interface and pass it to the client object with .setCallback() method (docs)
But at QOS 0 the callback will fire as soon as the client tries to send the message, there is no guarantee that the message will ever get there.
Related
I am working on an approach where i am required to send a message back to SQS.
I don't want it to go as a new message as that will reset the approximateRecieveCount parameter which is required by the code.
Please note that
I cannot send a NACK to the queue as i am reading it as a batch of 10 messages, I want to manually post it back in certain cases for individual message and not as a batch.
The code I am trying to use
I tried setting the JMSMessageId but it is not possible as according to the documentation -
After you send messages, Amazon SQS sets the following headers and properties for each message:
JMSMessageID
JMS_SQS_SequenceNumber (only for FIFO queues)
The code i am using right now is
defaultJmsTemplate.send(destinationName, new MessageCreator() {
#Override
public Message createMessage(Session session) throws JMSException {
Message message = session.createTextMessage(errorMessage);
message.setJMSCorrelationID(transactionId);
if (destinationName.endsWith(".fifo")) {
message.setStringProperty("JMSXGroupID", property.getMessageGroup());
message.setStringProperty("JMS_SQS_DeduplicationId", java.util.UUID.randomUUID().toString());
}
return message;
}
});
}
Is there anything that i can set/use to make sure the message is not treated as a new message and the approximate receive count is maintained?
Yes. This can be done. As you are using JMS for SQS while setting up your consumer you can define an UNORDERED_ACKNOWLEDGE mode in your consumer session. By doing so if you do not acknowledge a particular message it will be redelivered after its visibility timeout expires and the approximateRecieveCount will be incremented. This will not impact your other messages in the same batch. One downside of this is if you are using the fifo queue and the all your messages have same group id then you next message will only be processed after this unacknowledged message ends up in dead letter queue. This will only happen after your message is retried for the Maximum Receives that you have set up in fifo queue configuration. Note : The key here is to not acknowledge a particular message.
I am using the latest Paho version via Maven.
<dependency>
<groupId>org.eclipse.paho</groupId>
<artifactId>org.eclipse.paho.client.mqttv3</artifactId>
<version>1.2.2</version>
</dependency>
I create client using
MqttClient client = new MqttClient("tcp://localhost", MqttClient.generateClientId());
MqttConnectOptions options = new MqttConnectOptions();
options.setMaxInflight(1000);
options.setAutomaticReconnect(true);
Then I subscribe to a topic as follows:
client.setCallback(new Callback());
client.connect();
client.subscribe(topic);
Another mqtt client publishes a message on that topic with
MqttMessage message = new MqttMessage(byteStream);
message.setRetained(true);
With the retain flag I would expect that as soon as I subscribe, my callback is invoked. Unfortunately, the subscription callback is NOT called if the message is sent before the subscription is executed.
How do I get the retained value?
I think you are using QOS=0.
It is possible a retained message not saved with QOS=0 and retained_flag=true.
More details:
Reference link:
SECTION (3.3.1.3 RETAIN):
If the RETAIN flag is set to 1, in a PUBLISH Packet sent by a Client to a Server, the Server MUST store the Application Message and its QoS, so that it can be delivered to future subscribers whose subscriptions match its topic name [MQTT-3.3.1-5]. When a new subscription is established, the last retained message, if any, on each matching topic name MUST be sent to the subscriber [MQTT-3.3.1-6].
If the Server receives a QoS 0 message with the RETAIN flag set to 1 it MUST discard any message previously retained for that topic. It SHOULD store the new QoS 0 message as the new retained message for that topic, but MAY choose to discard it at any time - if this happens there will be no retained message for that topic [MQTT-3.3.1-7]. See Section 4.1 for more information on storing state.
Summary:
You can use QOS>0 to solve your problem.
Unfortunately, the subscription callback is NOT called if the message is sent before the subscription is executed. How do I get the retained value?
In this case, the publisher (one client) sends out message, immediately disconnects from MQTT broker (server), then the subscriber (another client) connects to the server with the same topic, Without last will message, it is not possible that the published message will be delivered to your subscriber.
There would be options in paho to enable last will message by setting :
will flag
will retain flag
will topic
will message (will payload)
retain flag in PUBLISH control packet (not the same as will retain flag)
Set up all of them when the publisher sends out the message with a topic, the sent message will be retained on MQTT broker even after the publisher closes network connection. At a later time when any subscriber (another client) connects to the broker with the same topic, the retained message will be sent from the broker to the subscriber.
Also please note that QoS field of PUBLISH control packet is for ensuring delivery is complete (at different level) ONLY between MQTT publisher and MQTT broker(server) , NOT between MQTT publisher and subscriber (the 2 clients).
I have implemented websocket client using okhttp 3.5.0 to connect to spring websocket server.
After websocket connection to server is successful, I subscribe to multiple topics to receive notifications from server. When a notification is received , if it takes long time to process that message in OnMessage function , I have observed that other incoming messages from server are enqueued and wait for the completion of first message .
Is there any way to make WebSocketListener OnMessage function concurrent, so that incoming messages does not wait for completion of any other older messages?
I tried delegating the handling of messages to a separate thread and that solved the issue of onMessage getting blocked but I want to know is there any other way to achieve the same.
This is my code to create websocket client
OkHttpClient client = new OkHttpClient.Builder()
.readTimeout(0, TimeUnit.MILLISECONDS).sslSocketFactory(sslSocketFactory, trustManager)
.build();
Request request = new Request.Builder()
.url(url)
.build();
WebSocketListenerExtension webSocketListenerExtension = new WebSocketListenerExtension();
client.newWebSocket(request, webSocketListenerExtension);
// Trigger shutdown of the dispatcher's executor so this process can exit cleanly.
client.dispatcher().executorService().shutdown();
I can't find documentation for reply processing with gateways and service activators.
If I have gateway which:
1) sends requests to channel ReqChannel
2) accepts replies on channel RepChannel
ReqChannel is connected to router, that routes incoming messages to one of some service activators, let say AServiceActivator and BServiceActivator and that service activators have a configured output-channel="RepChannel".
And if I execute more than one method call on gateway's interface asynchronously or simultaneously from different threads, how gateway will correlate incoming replies to actual service caller?
The gateway creates a temporary reply channel and puts it in the header of the message. This mechanism provides the necessary correlation because each message gets its own reply channel.
If the final consumer (say a service-activator) has no output-channel, the framework automatically sends the reply to the replyChannel header.
For this reason, it is generally not necessary to declare a reply-channel on the gateway for the final consumer to send to.
However, there are times when this is useful - such as if you want to wire-tap the reply channel, or make it a publish-subscribe channel, so the result goes to multiple places.
In this case (when there is a reply-channel on the gateway, and the final consumer sends a message there), the framework simply bridges the explicitly declared reply-channel to the temporary reply channel in the message header.
For this reason, it is critical to retain the replyChannel header in your flow. You can't send some arbitrary reply to a reply-channel, unless you include the original message's replyChannel header.
We are sending XML text messages via a remote queue definition CLIENT.DATA (transmit queue, send/recv channels etc.) from our queue manager QM_MINE queue manager QM_CLIENT and queue CLIENT.DATA. The message reaches the destination (CLIENT.DATA queue at the client's). The problem at hand is to able to receive acknowledgement messages (exact copy of the message sent) on a local queue CLIENT.DATA.ACK in QM_MINE as soon as messages reaches CLIENT.DATA in QM_CLIENT automatically.
I found couple of resources at WebSphere v7.1 infocenter on reply-to queue and message acknowledgement however they were not really helpful to me.
So far I tried to use the reply to queue way. I created a transmit queue QM_MCT on QM.OCC. Every message I send to the CLIENT.DATA queue, I specified the reply-queue using setJMSReplyTo() method. However I am sure that is not it, there is more I am missing.
MQ Objects Summary:
QM_MINE: CLIENT_DATA (remoteQ), QM_CLIENT (transmitQ), CLIENT_DATA_ACK(localQ)
QM_CLIENT: CLIENT_DATA (localQ), QM_MINE (transmitQ),
And, sender/receiver channels at both ends.
Source Code Fragements:
Client Data Sender (under transaction):
public class ClientServiceImpl extends JmsGatewaySupport implements ClientService {
#Override
public void sendClientData(String dataXML) {
getJmsTemplate().convertAndSend(dataXML);
}
}
Message Converter :
public Message toMessage(Object o, Session session) throws JMSException, MessageConversionException {
String dataXML = (String) o;
TextMessage message = session.createTextMessage();
message.setJMSReplyTo(replyToQueue);
message.setText(dataXML);
return message;
}
Note:
Current I don't have any MDP or MDB to listen and consume messages from CLIENT_DATA queue in QM_CLIENT. I merely send it from QM_MINE and it gets moved to QM_CLIENT by MQ. Do I need to consume the messages to get this working?
I use java, JMS , Spring and WebShere MQ v7.1 on Linux. Any more information will be provided upon request.
Please see the section on the MQMD.Report field. Yes, you do need to set the reply-to fields so that the acknowledgement can find its way back to you. However you also need to tell WMQ that you want it to generate the report message. For what you want, set the field to MQRO_COA_WITH_FULL_DATA.