// Process all messages for a particular client async Task <ISinkResult <IRoutingMessage> > ProcessClientMessages(string id, List <IRoutingMessage> routingMessages, CancellationToken token) { var succeeded = new List <IRoutingMessage>(); var failed = new List <IRoutingMessage>(); var invalid = new List <InvalidDetails <IRoutingMessage> >(); Devices.Routing.Core.Util.Option <SendFailureDetails> sendFailureDetails = Option.None <SendFailureDetails>(); // Find the maximum message size, and divide messages into largest batches // not exceeding max allowed IoTHub message size. long maxMessageSize = routingMessages.Select(r => r.Size()).Max(); int batchSize = GetBatchSize(Math.Min(this.cloudEndpoint.maxBatchSize, routingMessages.Count), maxMessageSize); foreach (IEnumerable <IRoutingMessage> batch in routingMessages.Batch(batchSize)) { ISinkResult res = await this.ProcessClientMessagesBatch(id, batch.ToList(), token); succeeded.AddRange(res.Succeeded); failed.AddRange(res.Failed); invalid.AddRange(res.InvalidDetailsList); sendFailureDetails = res.SendFailureDetails; } return(new SinkResult <IRoutingMessage>( succeeded, failed, invalid, sendFailureDetails.GetOrElse(null))); }
public async Task <ISinkResult> ProcessAsync(ICollection <IRoutingMessage> routingMessages, CancellationToken token) { Preconditions.CheckNotNull(routingMessages, nameof(routingMessages)); var succeeded = new List <IRoutingMessage>(); var failed = new List <IRoutingMessage>(); var invalid = new List <InvalidDetails <IRoutingMessage> >(); Devices.Routing.Core.Util.Option <SendFailureDetails> sendFailureDetails = Option.None <SendFailureDetails>(); Events.ProcessingMessages(routingMessages); foreach (IRoutingMessage routingMessage in routingMessages) { if (token.IsCancellationRequested) { break; } ISinkResult res = await this.ProcessAsync(routingMessage, token); succeeded.AddRange(res.Succeeded); failed.AddRange(res.Failed); invalid.AddRange(res.InvalidDetailsList); sendFailureDetails = res.SendFailureDetails; } return(new SinkResult <IRoutingMessage>( succeeded, failed, invalid, sendFailureDetails.GetOrElse(null))); }
async Task <ISinkResult> ProcessByClients(ICollection <IRoutingMessage> routingMessages, CancellationToken token) { var routingMessageGroups = (from r in routingMessages group r by this.GetIdentity(r) into g select new { Id = g.Key, RoutingMessages = g.ToList() }) .ToList(); var succeeded = new List <IRoutingMessage>(); var failed = new List <IRoutingMessage>(); var invalid = new List <InvalidDetails <IRoutingMessage> >(); Devices.Routing.Core.Util.Option <SendFailureDetails> sendFailureDetails = Option.None <SendFailureDetails>(); Events.ProcessingMessageGroups(routingMessages, routingMessageGroups.Count, this.cloudEndpoint.FanOutFactor); foreach (var groupBatch in routingMessageGroups.Batch(this.cloudEndpoint.FanOutFactor)) { IEnumerable <Task <ISinkResult <IRoutingMessage> > > sendTasks = groupBatch .Select(item => this.ProcessClientMessages(item.Id, item.RoutingMessages, token)); ISinkResult <IRoutingMessage>[] sinkResults = await Task.WhenAll(sendTasks); foreach (ISinkResult <IRoutingMessage> res in sinkResults) { succeeded.AddRange(res.Succeeded); failed.AddRange(res.Failed); invalid.AddRange(res.InvalidDetailsList); // Different branches could have different results, but only the first one will be reported if (!sendFailureDetails.HasValue) { sendFailureDetails = res.SendFailureDetails; } } } return(new SinkResult <IRoutingMessage>( succeeded, failed, invalid, sendFailureDetails.GetOrElse(null))); }