protected async Task CheckPendingMessages(string endPointID) { ASSERT(!string.IsNullOrWhiteSpace(endPointID), $"Missing parameter '{nameof(endPointID)}"); // Is this endpoint registered against me ? lock ( Locker ) { if (!RegisteredEndpoints.ContainsKey(endPointID)) { // No -> No need to continue return; } } var messages = await RestoreMessages(endPointID); if (messages == null) { // No messages available for this endpoint return; } IEndPoint endPoint; lock ( Locker ) { endPoint = RegisteredEndpoints.TryGet(endPointID); if (endPoint == null) { // endPoint was unregistered in the mean-time (nb: should not happen often ...) goto PUSH_MESSAGES_BACK; } else if (endPoint.IsOneShot) { // Unregister this endpoint before sending the messages var rc = RegisteredEndpoints.Remove(endPointID); ASSERT(rc, $"Could not unregister endpoint '{endPointID}'"); goto SEND_MESSAGES; } else // not one-shot { goto SEND_MESSAGES; } } #pragma warning disable 0162 FAIL("Unreachable code reached ..."); #pragma warning restore 0162 SEND_MESSAGES: ASSERT(endPoint != null, $"Logic error: '{nameof(endPoint)}' is supposed to be set here"); await endPoint.ReceiveMessages(messages); return; PUSH_MESSAGES_BACK: // The messages could not be delivered => Put them back in the queue await ReceiveMessages(messages); return; }
public Task UnRegisterEndpoint(string id) { ASSERT(!string.IsNullOrWhiteSpace(id), $"Missing parameter '{nameof(id)}"); lock ( Locker ) { var rc = RegisteredEndpoints.Remove(id); ASSERT(rc, $"Could not unregister endpoint '{id}'"); // nb: can happen in case of race condition, but should be very rare } return(Task.FromResult(0)); }
public async Task ReceiveMessages(IEnumerable <TMessage> messages) { ASSERT(messages != null, $"Missing parameter '{nameof(messages)}'"); ASSERT(messages.Where(v => string.IsNullOrWhiteSpace(v.TryGetString(MessageKeys.KeyReceiverID))).Count() == 0, $"There are messages without '{MessageKeys.KeyReceiverID}' defined"); var messagesToSave = (new{ EndPointID = (string)null, Messages = (List <TMessage>)null }).NewAnonymousList(); var messagesToSend = (new{ EndPoint = (IEndPoint)null, Messages = (List <TMessage>)null }).NewAnonymousList(); var byEndPointIDs = messages.GroupBy(v => v.TryGetString(MessageKeys.KeyReceiverID)).ToDictionary(v => v.Key, v => v.ToList()); lock ( Locker ) { foreach (var pair in byEndPointIDs) { var endPointID = pair.Key; var msgs = pair.Value; var endPoint = RegisteredEndpoints.TryGet(endPointID); if (endPoint == null) { // These messages are for an endpoint that is not managed by me => Save them to Redis messagesToSave.Add(new{ EndPointID = endPointID, Messages = msgs }); } else if (endPoint.IsOneShot) { // These messages are for an endpoint that is managed by me but needs to be unregistered when it receives messages var rc = RegisteredEndpoints.Remove(endPointID); ASSERT(rc, $"Could not unregister endpoint '{endPointID}'"); messagesToSend.Add(new{ EndPoint = endPoint, Messages = msgs }); } else { // These messages are for an endpoint that is managed by me messagesToSend.Add(new{ EndPoint = endPoint, Messages = msgs }); } } } var exception = (System.Exception)null; // The first exception encountered if any foreach (var item in messagesToSend) { var notAwaited = Task.Run(async() => // nb: Run asynchroneously { try { await item.EndPoint.ReceiveMessages(item.Messages); } catch (System.Exception ex) { exception = (exception ?? ex); } }); } foreach (var item in messagesToSave) { try { await SaveMessages(item.EndPointID, item.Messages); } catch (System.Exception ex) { exception = (exception ?? ex); } } if (exception != null) { // An exception has been encountered => Rethrow the first one received throw new ApplicationException($"An error occurred while receiving a message ({exception.GetType().FullName}): {exception.Message}", innerException: exception); } }