/// <summary> /// Returns all messages sent given a matching Message ID. /// </summary> /// <param name="MsgID"></param> private RequestState[] GetStatesByID(long MsgID) { // In case the id referenced the message id if (PendingQueue.TryRemove(MsgID, out var state)) { return new RequestState[] { state } } ; // In case the id is a container id var FromContainer = PendingQueue.Values .Where(x => x.ContainerID == MsgID) .Select(x => GetStatesByID(x.MessageID)) .Join(); if (FromContainer.Count() > 0) { return(FromContainer); } // In case the id refers to an ack var AlreadySend = SentAcks.Read() .Where(x => x.MessageID == MsgID) .ToArray(); if (AlreadySend.Count() > 0) { return(AlreadySend); } // When all else fails return(null); }
private async Task AckHandlerMethod(CancellationToken cancellationToken) { while (!cancellationToken.IsCancellationRequested) { try { // Send every three minutes await Task.Delay(3 * 60 * 1000, cancellationToken); // Don't run this time if there aren't any messages to acknowledge if (!PendingAcks.Any()) { continue; } // Take all the required acks out of the bag var acks = new List <long>(); while (PendingAcks.TryTake(out var ack)) { acks.Add(ack); } Logger.Log(Logger.Level.Debug, $"Found {acks.Count} messages that need acknowledgement. Adding them to the payload."); // Create a request that contains the list of acks var Acks_Request = new RequestState(Schema.msgs_ack(new { msg_ids = acks })); // Add the request to both the send queue (to be sent to the server) and // the sent acks queue (in case we need to resend. We don't want to place // in pending since there shouldn't be a response. SendQueue.Add(Acks_Request); SentAcks.Put(Acks_Request); // Send the acks to the server // ToDo: If the user will be polling for updates, can we skip this line // and let the acks be sent for us? Task unawaited = Task.Run(() => ProcessSendQueue()); } catch (TaskCanceledException) { // We don't really care if the task was cancelled. break; } catch (ObjectDisposedException) { // We don't really care if the task was cancelled. break; } catch (Exception ex) { // ToDo: Do we really want to skip all acks when this happens? Likely we // will encounter the same error again if we reprocess... Logger.Log(Logger.Level.Error, $"An error occurred process acks. Skipping.\n\n{ex.Message}"); } } }