Handle publish errors properly in PersistentQueueMessageSender. Create a connection descriptor store to handle all the message delivery errors and to avoid

duplicating error handling code (i.e. the connection descriptors map is null, the connection descriptor does not exist, etc).
This commit is contained in:
Luis Barrios
2017-01-11 11:23:24 +01:00
parent 63d106e414
commit 7666a1634a
7 changed files with 197 additions and 88 deletions
@@ -1,13 +1,11 @@
package io.moquette.spi.impl;
import io.moquette.parser.proto.messages.PublishMessage;
import io.moquette.server.ConnectionDescriptor;
import io.moquette.server.ConnectionDescriptorStore;
import io.moquette.spi.ClientSession;
import io.netty.channel.Channel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.concurrent.ConcurrentMap;
import static io.moquette.parser.proto.messages.AbstractMessage.QOSType.MOST_ONE;
import static io.moquette.spi.impl.ProtocolProcessor.asStoredMessage;
@@ -15,41 +13,34 @@ import static io.moquette.spi.impl.ProtocolProcessor.asStoredMessage;
class PersistentQueueMessageSender {
private static final Logger LOG = LoggerFactory.getLogger(PersistentQueueMessageSender.class);
private final ConcurrentMap<String, ConnectionDescriptor> connectionDescriptors;
private final ConnectionDescriptorStore connectionDescriptorStore;
public PersistentQueueMessageSender(ConcurrentMap<String, ConnectionDescriptor> connectionDescriptors) {
this.connectionDescriptors = connectionDescriptors;
public PersistentQueueMessageSender(ConnectionDescriptorStore connectionDescriptorStore) {
this.connectionDescriptorStore = connectionDescriptorStore;
}
void sendPublish(ClientSession clientsession, PublishMessage pubMessage) {
String clientId = clientsession.clientID;
LOG.info("send publish message to <{}> on topic <{}>", clientId, pubMessage.getTopicName());
if (LOG.isDebugEnabled()) {
LOG.debug("directSend invoked clientId <{}> on topic <{}> QoS {} retained {} messageID {}",
clientId, pubMessage.getTopicName(), pubMessage.getQos(), false, pubMessage.getMessageID());
LOG.debug("content <{}>", DebugUtils.payload2Str(pubMessage.getPayload()));
LOG.debug("Sending PUBLISH message. MessageId = {}, mqttClientId = {}, topic = {}, qos = {}, payload = {}.",
pubMessage.getMessageID(),
clientId, pubMessage.getTopicName(), DebugUtils.payload2Str(pubMessage.getPayload()));
} else {
LOG.info("Sending PUBLISH message. MessageId = {}, mqttClientId = {}, topic = {}.", pubMessage.getMessageID(),
clientId, pubMessage.getTopicName());
}
if (connectionDescriptors == null) {
throw new RuntimeException("Internal bad error, found connectionDescriptors to null while it should be " +
"initialized, somewhere it's overwritten!!");
}
if (connectionDescriptors.get(clientId) == null) {
//TODO while we were publishing to the target client, that client disconnected,
// could happen is not an error HANDLE IT
throw new RuntimeException(String.format("Can't find a ConnectionDescriptor for client <%s> in cache <%s>",
clientId, connectionDescriptors));
}
Channel channel = connectionDescriptors.get(clientId).channel;
LOG.trace("Session for clientId {}", clientId);
if (channel.isWritable()) {
LOG.debug("channel is writable");
//if channel is writable don't enqueue
channel.writeAndFlush(pubMessage);
} else if (pubMessage.getQos() != MOST_ONE) {
//enqueue to the client session
LOG.debug("enqueue to client session");
clientsession.enqueue(asStoredMessage(pubMessage));
}
boolean messageDelivered = connectionDescriptorStore.sendMessage(pubMessage, pubMessage.getMessageID(), clientId);
if (!messageDelivered && pubMessage.getQos() != MOST_ONE && !clientsession.isCleanSession()) {
LOG.warn(
"The PUBLISH message could not be delivered. It will be stored. MessageId = {}, mqttClientId = {}, topic = {}, qos = {}, cleanSession = {}.",
pubMessage.getMessageID(), clientId, pubMessage.getTopicName(), pubMessage.getQos(), false);
clientsession.enqueue(asStoredMessage(pubMessage));
} else {
LOG.warn(
"The PUBLISH message could not be delivered. It will be discarded. MessageId = {}, mqttClientId = {}, topic = {}, qos = {}, cleanSession = {}.",
pubMessage.getMessageID(), clientId, pubMessage.getTopicName(), pubMessage.getQos(), true);
}
}
}