GH-3697: Various lifecycle fixed for MQTT v5 CAs
Fixes https://github.com/spring-projects/spring-integration/issues/3697 SO: https://stackoverflow.com/questions/70374046/spring-integration-mqtt-failed-to-start-app-when-the-network-is-disconnected * Add `mqttClient.disconnect()` to `Mqttv5PahoMessageDrivenChannelAdapter.doStop()` - the `doStart()` does `connect()` * Add `Mqttv5PahoMessageDrivenChannelAdapter.destroy()` impl to close `mqttClient` * Fix `Mqttv5PahoMessageHandler.doStart()` to not re-throw an exception on connection. Emit an `MqttConnectionFailedEvent` and log error instead * Fix `Mqttv5PahoMessageHandler.destroy()` to call `mqttClient.close(true)` for better resources clean up * Improve MQTT v5 components Javadocs and add a reconnect note into `mqtt.adoc`
This commit is contained in:
committed by
Gary Russell
parent
30bb8467b4
commit
8c57cb7869
@@ -59,7 +59,7 @@ import org.springframework.util.Assert;
|
||||
*
|
||||
* It is recommended to have the {@link MqttConnectionOptions#setAutomaticReconnect(boolean)}
|
||||
* set to true to let an internal {@link IMqttAsyncClient} instance to handle reconnects.
|
||||
* Otherwise, the manual restart of this component can only handle reconnects, e.g. via
|
||||
* Otherwise, only the manual restart of this component can handle reconnects, e.g. via
|
||||
* {@link MqttConnectionFailedEvent} handling on disconnection.
|
||||
*
|
||||
* See {@link #setPayloadType} for more information about type conversion.
|
||||
@@ -190,6 +190,7 @@ public class Mqttv5PahoMessageDrivenChannelAdapter extends AbstractMqttMessageDr
|
||||
String[] topics = getTopic();
|
||||
try {
|
||||
this.mqttClient.unsubscribe(topics).waitForCompletion(getCompletionTimeout());
|
||||
this.mqttClient.disconnect().waitForCompletion(getCompletionTimeout());
|
||||
}
|
||||
catch (MqttException ex) {
|
||||
logger.error(ex, () -> "Error unsubscribing from " + Arrays.toString(topics));
|
||||
@@ -199,6 +200,17 @@ public class Mqttv5PahoMessageDrivenChannelAdapter extends AbstractMqttMessageDr
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
super.destroy();
|
||||
try {
|
||||
this.mqttClient.close(true);
|
||||
}
|
||||
catch (MqttException ex) {
|
||||
logger.error(ex, "Failed to close 'MqttAsyncClient'");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addTopic(String topic, int qos) {
|
||||
this.topicLock.lock();
|
||||
|
||||
@@ -50,6 +50,12 @@ import org.springframework.util.Assert;
|
||||
/**
|
||||
* The {@link AbstractMqttMessageHandler} implementation for MQTT v5.
|
||||
*
|
||||
* It is recommended to have the {@link MqttConnectionOptions#setAutomaticReconnect(boolean)}
|
||||
* set to true to let an internal {@link IMqttAsyncClient} instance to handle reconnects.
|
||||
* Otherwise, only the manual restart of this component can handle reconnects, e.g. via
|
||||
* {@link MqttConnectionFailedEvent} handling on disconnection.
|
||||
*
|
||||
*
|
||||
* @author Artem Bilan
|
||||
*
|
||||
* @since 5.5.5
|
||||
@@ -159,7 +165,11 @@ public class Mqttv5PahoMessageHandler extends AbstractMqttMessageHandler
|
||||
this.mqttClient.connect(this.connectionOptions).waitForCompletion(getCompletionTimeout());
|
||||
}
|
||||
catch (MqttException ex) {
|
||||
throw new IllegalStateException("Cannot connect 'MqttAsyncClient' for: " + getComponentName(), ex);
|
||||
ApplicationEventPublisher applicationEventPublisher = getApplicationEventPublisher();
|
||||
if (applicationEventPublisher != null) {
|
||||
applicationEventPublisher.publishEvent(new MqttConnectionFailedEvent(this, ex));
|
||||
}
|
||||
logger.error(ex, "MQTT client failed to connect. Will retry if 'ConnectionOptions.isAutomaticReconnect()'.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -177,7 +187,7 @@ public class Mqttv5PahoMessageHandler extends AbstractMqttMessageHandler
|
||||
public void destroy() {
|
||||
super.destroy();
|
||||
try {
|
||||
this.mqttClient.close();
|
||||
this.mqttClient.close(true);
|
||||
}
|
||||
catch (MqttException ex) {
|
||||
logger.error(ex, "Failed to close 'MqttAsyncClient'");
|
||||
|
||||
@@ -56,7 +56,7 @@ import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
|
||||
* @author Gary Russell
|
||||
* @author Artem Bilan
|
||||
*
|
||||
* @since 4.0
|
||||
* @since 5.5.5
|
||||
*
|
||||
*/
|
||||
@SpringJUnitConfig
|
||||
@@ -164,8 +164,7 @@ public class Mqttv5BackToBackTests implements MosquittoContainerTest {
|
||||
messageProducer.setMessageConverter(mqttStringToBytesConverter());
|
||||
messageProducer.setManualAcks(true);
|
||||
|
||||
return IntegrationFlows.from(
|
||||
messageProducer)
|
||||
return IntegrationFlows.from(messageProducer)
|
||||
.channel(c -> c.queue("fromMqttChannel"))
|
||||
.get();
|
||||
}
|
||||
|
||||
@@ -494,4 +494,7 @@ public IntegrationFlow mqttInFlow() {
|
||||
|
||||
IMPORTANT: The `org.springframework.integration.mqtt.support.MqttMessageConverter` cannot be used with the `Mqttv5PahoMessageDrivenChannelAdapter` since its contract is aimed only for the MQTT v3 protocol.
|
||||
|
||||
See more information in the `Mqttv5PahoMessageDrivenChannelAdapter` javadocs and its superclass.
|
||||
See more information in the `Mqttv5PahoMessageDrivenChannelAdapter` javadocs and its superclass.
|
||||
|
||||
IMPORTANT: It is recommended to have the `MqttConnectionOptions#setAutomaticReconnect(boolean)` set to true to let an internal `IMqttAsyncClient` instance to handle reconnects.
|
||||
Otherwise, only the manual restart of these channel adapters can handle reconnects, e.g. via `MqttConnectionFailedEvent` handling on disconnection.
|
||||
Reference in New Issue
Block a user