Example #1
0
        async Task AcknowledgePublishAsync(IChannelHandlerContext context, AckPendingMessageState message)
        {
            this.ResumeReadingIfNecessary(context);

            // todo: is try-catch needed here?
            try
            {
                await message.FeedbackChannel.CompleteAsync();

                PerformanceCounters.OutboundMessageProcessingTime.Register(message.StartTimestamp);

                this.publishPubAckProcessor.ResumeRetransmission(context);
            }
            catch (Exception ex)
            {
                ShutdownOnError(context, "-> PUBACK", ex);
            }
        }
Example #2
0
        async Task AcknowledgePublishReceiveAsync(IChannelHandlerContext context, AckPendingMessageState message)
        {
            this.ResumeReadingIfNecessary(context);

            // todo: is try-catch needed here?
            try
            {
                IQos2MessageDeliveryState messageInfo = this.qos2StateProvider.Create(message.SequenceNumber);
                await this.qos2StateProvider.SetMessageAsync(this.identity, message.PacketId, messageInfo);

                await this.PublishReleaseToClientAsync(context, message.PacketId, message.FeedbackChannel, messageInfo, message.StartTimestamp);

                this.publishPubRecProcessor.ResumeRetransmission(context);
            }
            catch (Exception ex)
            {
                ShutdownOnError(context, "-> PUBREC", ex);
            }
        }
        async void RetransmitNextPublish(IChannelHandlerContext context, AckPendingMessageState messageInfo)
        {
            bool wasReceiving = this.IsInState(StateFlags.Receiving);

            try
            {
                await this.messagingServiceClient.AbandonAsync(messageInfo.LockToken);

                if (!wasReceiving)
                {
                    this.Receive(context);
                }
            }
            catch (MessagingException ex)
            {
                this.ShutdownOnReceiveError(context, ex.ToString());
            }
            catch (Exception ex)
            {
                ShutdownOnError(context, ex.ToString());
            }
        }
        async Task AcknowledgePublishAsync(IChannelHandlerContext context, AckPendingMessageState message)
        {
            this.ResumeReadingIfNecessary(context);

            // todo: is try-catch needed here?
            try
            {
                await this.messagingServiceClient.CompleteAsync(message.LockToken);

                PerformanceCounters.OutboundMessageProcessingTime.Register(message.StartTimestamp);

                if (this.publishPubAckProcessor.ResumeRetransmission(context))
                {
                    return;
                }

                this.RestartReceiveIfPossible(context);
            }
            catch (Exception ex)
            {
                ShutdownOnError(context, "-> PUBACK", ex);
            }
        }
        async void RetransmitPublishMessage(IChannelHandlerContext context, IMessage message, AckPendingMessageState messageInfo)
        {
            try
            {
                using (message)
                {
                    string topicName;
                    message.Properties[TemplateParameters.DeviceIdTemplateParam] = this.DeviceId;
                    if (!this.messageRouter.TryRouteOutgoingMessage(RouteSourceType.Notification, message, out topicName))
                    {
                        throw new InvalidOperationException("Route mapping failed on retransmission.");
                    }

                    PublishPacket packet = await Util.ComposePublishPacketAsync(context, message, messageInfo.QualityOfService, topicName, context.Channel.Allocator);

                    messageInfo.ResetMessage(message);
                    await this.publishPubAckProcessor.RetransmitAsync(context, packet, messageInfo);
                }
            }
            catch (Exception ex)
            {
                // todo: log more details
                ShutdownOnError(context, "<- PUBLISH (retransmission)", ex);
            }
        }
        async void Receive(IChannelHandlerContext context)
        {
            try
            {
                IMessage message = await this.messagingServiceClient.ReceiveAsync();

                if (message == null)
                {
                    // link to IoT Hub has been closed
                    this.ShutdownOnReceiveError(context, null);
                    return;
                }

                PerformanceCounters.MessagesReceivedPerSecond.Increment();

                bool receiving = this.IsInState(StateFlags.Receiving);
                int  processorsInRetransmission = 0;
                bool messageSent = false;

                if (this.publishPubAckProcessor.Retransmitting)
                {
                    processorsInRetransmission++;
                    AckPendingMessageState pendingPubAck = this.publishPubAckProcessor.FirstRequestPendingAck;
                    if (pendingPubAck.SequenceNumber == message.SequenceNumber)
                    {
                        this.RetransmitPublishMessage(context, message, pendingPubAck);
                        messageSent = true;
                    }
                }

                if (this.publishPubRecProcessor.Retransmitting)
                {
                    processorsInRetransmission++;
                    if (!messageSent)
                    {
                        AckPendingMessageState pendingPubRec = this.publishPubRecProcessor.FirstRequestPendingAck;
                        if (pendingPubRec.SequenceNumber == message.SequenceNumber)
                        {
                            this.RetransmitPublishMessage(context, message, pendingPubRec);
                            messageSent = true;
                        }
                    }
                }

                if (processorsInRetransmission == 0)
                {
                    this.PublishToClientAsync(context, message).OnFault(ShutdownOnPublishFaultAction, context);
                    if (!this.IsInState(StateFlags.Closed) &&
                        (this.MessagePendingAckCount < this.settings.MaxPendingOutboundMessages))
                    {
                        this.Receive(context); // todo: review for potential stack depth issues
                    }
                    else
                    {
                        this.ResetState(StateFlags.Receiving);
                    }
                }
                else
                {
                    if (receiving)
                    {
                        if (!messageSent)
                        {
                            // message id is different - "publish" this message (it actually will be enqueued for future retransmission immediately)
                            await this.PublishToClientAsync(context, message);
                        }
                        this.ResetState(StateFlags.Receiving);
                        for (int i = processorsInRetransmission - (messageSent ? 1 : 0); i > 0; i--)
                        {
                            // fire receive for processors that went into retransmission but held off receiving messages due to ongoing receive call
                            this.Receive(context); // todo: review for potential stack depth issues
                        }
                    }
                    else if (!messageSent)
                    {
                        throw new InvalidOperationException("Received a message that does not match");
                    }
                }
            }
            catch (MessagingException ex)
            {
                this.ShutdownOnReceiveError(context, ex.ToString());
            }
            catch (Exception ex)
            {
                ShutdownOnError(context, "Receive", ex.ToString());
            }
        }
Example #7
0
        async void RetransmitPublishMessage(IChannelHandlerContext context, MessageWithFeedback messageWithFeedback, AckPendingMessageState messageInfo)
        {
            PublishPacket packet = null;

            try
            {
                using (IMessage message = messageWithFeedback.Message)
                {
                    message.Properties[TemplateParameters.DeviceIdTemplateParam] = this.DeviceId;
                    packet = Util.ComposePublishPacket(context, message, messageInfo.QualityOfService, context.Channel.Allocator);
                    messageInfo.ResetMessage(message, messageWithFeedback.FeedbackChannel);
                    await this.publishPubAckProcessor.RetransmitAsync(context, packet, messageInfo);
                }
            }
            catch (Exception ex)
            {
                ReferenceCountUtil.SafeRelease(packet);
                ShutdownOnError(context, "<- PUBLISH (retransmission)", ex);
            }
        }
        async void RetransmitPublishMessage(IChannelHandlerContext context, Message message, AckPendingMessageState messageInfo)
        {
            try
            {
                using (message)
                {
                    string topicName;
                    var completeContext = new ReadOnlyMergeDictionary<string, string>(this.sessionContext, message.Properties);
                    if (!this.topicNameRouter.TryMapRouteToTopicName(RouteSourceType.Notification, completeContext, out topicName))
                    {
                        throw new InvalidOperationException("Route mapping failed on retransmission.");
                    }

                    PublishPacket packet = await Util.ComposePublishPacketAsync(context, message, messageInfo.QualityOfService, topicName);

                    messageInfo.ResetMessage(message);
                    await this.publishPubAckProcessor.RetransmitAsync(context, packet, messageInfo);
                }
            }
            catch (Exception ex)
            {
                // todo: log more details
                ShutdownOnError(context, "<- PUBLISH (retransmission)", ex);
            }
        }
Example #9
0
        public async void Handle(MessageWithFeedback messageWithFeedback)
        {
            IChannelHandlerContext context = this.capturedContext;
            IMessage message = messageWithFeedback.Message;

            try
            {
                Contract.Assert(message != null);

                PerformanceCounters.MessagesReceivedPerSecond.Increment();

                int  processorsInRetransmission = 0;
                bool sentThroughRetransmission  = false;

                if (this.publishPubAckProcessor.Retransmitting)
                {
                    processorsInRetransmission++;
                    AckPendingMessageState pendingPubAck = this.publishPubAckProcessor.FirstRequestPendingAck;
                    if (pendingPubAck.SequenceNumber == message.SequenceNumber)
                    {
                        this.RetransmitPublishMessage(context, messageWithFeedback, pendingPubAck);
                        sentThroughRetransmission = true;
                    }
                }

                if (this.publishPubRecProcessor.Retransmitting)
                {
                    processorsInRetransmission++;
                    if (!sentThroughRetransmission)
                    {
                        AckPendingMessageState pendingPubRec = this.publishPubRecProcessor.FirstRequestPendingAck;
                        if (pendingPubRec.SequenceNumber == message.SequenceNumber)
                        {
                            this.RetransmitPublishMessage(context, messageWithFeedback, pendingPubRec);
                            sentThroughRetransmission = true;
                        }
                    }
                }

                if (processorsInRetransmission == 0)
                {
                    this.PublishToClientAsync(context, messageWithFeedback).OnFault(ShutdownOnPublishFaultAction, context);
                }
                else
                {
                    if (!sentThroughRetransmission)
                    {
                        // message id is different - "publish" this message (it actually will be enqueued for future retransmission immediately)
                        await this.PublishToClientAsync(context, messageWithFeedback);

                        // todo: consider back pressure in a form of explicit retransmission state communication with MSC
                    }
                }

                message = null;
            }
            catch (MessagingException ex)
            {
                this.ShutdownOnReceiveError(ex);
            }
            catch (Exception ex)
            {
                ShutdownOnError(context, ReceiveProcessingScope, ex);
            }
            finally
            {
                if (message != null)
                {
                    ReferenceCountUtil.SafeRelease(message.Payload);
                }
            }
        }
        async void RetransmitNextPublish(IChannelHandlerContext context, AckPendingMessageState messageInfo)
        {
            bool wasReceiving = this.IsInState(StateFlags.Receiving);

            try
            {
                await this.iotHubClient.AbandonAsync(messageInfo.LockToken);

                if (!wasReceiving)
                {
                    this.Receive(context);
                }
            }
            catch (IotHubException ex)
            {
                this.ShutdownOnReceiveError(context, ex.ToString());
            }
            catch (Exception ex)
            {
                ShutdownOnError(context, ex.ToString());
            }
        }
        async Task AcknowledgePublishReceiveAsync(IChannelHandlerContext context, AckPendingMessageState message)
        {
            this.ResumeReadingIfNecessary(context);

            // todo: is try-catch needed here?
            try
            {
                IQos2MessageDeliveryState messageInfo = this.qos2StateProvider.Create(message.MessageId);
                await this.qos2StateProvider.SetMessageAsync(message.PacketId, messageInfo);

                await this.PublishReleaseToClientAsync(context, message.PacketId, message.LockToken, messageInfo, message.StartTimestamp);

                if (this.publishPubRecProcessor.ResumeRetransmission(context))
                {
                    return;
                }

                this.RestartReceiveIfPossible(context);
            }
            catch (Exception ex)
            {
                ShutdownOnError(context, "-> PUBREC", ex);
            }
        }
        async Task AcknowledgePublishAsync(IChannelHandlerContext context, AckPendingMessageState message)
        {
            this.ResumeReadingIfNecessary(context);

            // todo: is try-catch needed here?
            try
            {
                await this.iotHubClient.CompleteAsync(message.LockToken);

                PerformanceCounters.OutboundMessageProcessingTime.Register(message.StartTimestamp);

                if (this.publishPubAckProcessor.ResumeRetransmission(context))
                {
                    return;
                }

                this.RestartReceiveIfPossible(context);
            }
            catch (Exception ex)
            {
                ShutdownOnError(context, "-> PUBACK", ex);
            }
        }
        async void RetransmitPublishMessage(IChannelHandlerContext context, Message message, AckPendingMessageState messageInfo)
        {
            try
            {
                using (message)
                {
                    string topicName;
                    var    completeContext = new ReadOnlyMergeDictionary <string, string>(this.sessionContext, message.Properties);
                    if (!this.topicNameRouter.TryMapRouteToTopicName(RouteSourceType.Notification, completeContext, out topicName))
                    {
                        throw new InvalidOperationException("Route mapping failed on retransmission.");
                    }

                    PublishPacket packet = await Util.ComposePublishPacketAsync(context, message, messageInfo.QualityOfService, topicName);

                    messageInfo.ResetMessage(message);
                    await this.publishPubAckProcessor.RetransmitAsync(context, packet, messageInfo);
                }
            }
            catch (Exception ex)
            {
                // todo: log more details
                ShutdownOnError(context, "<- PUBLISH (retransmission)", ex);
            }
        }
        async void RetransmitPublishMessage(IChannelHandlerContext context, IMessage message, AckPendingMessageState messageInfo)
        {
            try
            {
                using (message)
                {
                    string topicName;
                    message.Properties[TemplateParameters.DeviceIdTemplateParam] = this.DeviceId;
                    if (!this.messageRouter.TryRouteOutgoingMessage(RouteSourceType.Notification, message, out topicName))
                    {
                        throw new InvalidOperationException("Route mapping failed on retransmission.");
                    }

                    PublishPacket packet = await Util.ComposePublishPacketAsync(context, message, messageInfo.QualityOfService, topicName, context.Channel.Allocator);

                    messageInfo.ResetMessage(message);
                    await this.publishPubAckProcessor.RetransmitAsync(context, packet, messageInfo);
                }
            }
            catch (Exception ex)
            {
                // todo: log more details
                ShutdownOnError(context, "<- PUBLISH (retransmission)", ex);
            }
        }