private async Task SendMessageAsync(ApolloQueue queue, Lazy <IMessageSender> sender, IMessage[] messages) { if (messages == null || !messages.Any()) { return; } if (!messages.All(m => m is ServiceBusMessage)) { throw new InvalidOperationException($"{GetType().Name} cannot send messages which do not inherit from {nameof(ServiceBusMessage)}"); } try { await sender.Value.SendAsync(messages.Select(m => ((ServiceBusMessage)m).InnerMessage).ToArray()); foreach (var message in messages) { OnMessageSent(message, queue); } } catch (Exception ex) { Logger.Warn(ex); throw; } }
private MessageStatus OnRegistrationReceived(ApolloQueue queue, IMessage m, CancellationToken?cancelToken) { Logger.Info($"Received registration request from {m.Identifier}"); if (_storage.SaveRegistration(m.ReplyToSession, m.Properties.ToDictionary(p => p.Key, p => p.Value.ToString()))) { Communicator.SendToClientsAsync(Communicator.MessageFactory.CreateAcknowledgment(m)); } return(MessageStatus.Complete); }
private void InvokeMessageHandlers(ApolloQueue queue, IMessage message, CancellationToken?token) { if (message == null) { return; } try { if (Handlers.TryGetValue(queue, out var handlers)) { var status = MessageStatus.Unhandled; foreach (var handler in handlers.Where(h => h.PassesFilter(message))) { try { if (token?.IsCancellationRequested ?? false) { return; } status = handler.HandleMessage(queue, message, token); if (status.HasFlag(MessageStatus.Handled)) { break; } } catch (Exception ex) { _service.AsyncListeningExceptions.Add(ExceptionDispatchInfo.Capture(ex)); _logger?.WriteLine($"{ex.Message} (This would normally be suppressed by the system)"); throw; } } if (message.Label == ApolloConstants.PositiveAcknowledgement || message.Label == ApolloConstants.NegativeAcknowledgement) { return; } if (status == MessageStatus.Unhandled) { throw new Exception($"{_identifier} received a message from {queue} with label '{message.Label}' which no handler could handle"); } if (!status.HasFlag(MessageStatus.MarkedForDeletion)) { _service.Enqueue(message, queue, _identifier); } } else { Debug.Assert(false, "Received a message without having any handlers!"); } } catch (Exception ex) { _logger?.WriteLine($"{ex.Message} (This would normally be suppressed by the system)"); _service.AsyncListeningExceptions.Add(ExceptionDispatchInfo.Capture(ex)); } }
protected virtual MessageStatus HandlePing(ApolloQueue targetQueue, IMessage message, CancellationToken?token) { var response = MessageFactory.CreateAcknowledgment(message); response[nameof(PingStats.ServedBy)] = Communicator.GetState <string>(ApolloConstants.RegisteredAsKey); response[nameof(PingStats.TimeRequestEnqueuedUtc)] = message.EnqueuedTimeUtc; Communicator.SendToClientsAsync(response); return(MessageStatus.Complete); }
public ConcurrentQueue <MockMessage> GetQueue(ApolloQueue queueType, string targetSession) { if (NormalQueues.TryGetValue(queueType, out var queue)) { if (targetSession != null) { throw new InvalidOperationException("Tried to send a message to a session in a queue without sessions enabled"); } return(queue); } return(GetSessionQueue(queueType, targetSession)); }
private MessageStatus LostOwnershipNotificationReceived(ApolloQueue queue, IMessage m, CancellationToken?cancelToken) { var alias = m.GetStringProperty(DesiredAliasKey); if (string.IsNullOrWhiteSpace(alias)) { return(MessageStatus.Complete); } Logger.Warn($"Lost ownership of alias '{alias}'"); LostOwnershipOfAlias?.Invoke(alias); return(MessageStatus.Complete); }
private MessageStatus AliasOwnershipRequestReceived(ApolloQueue queue, IMessage m, CancellationToken?cancelToken) { if (_storage.CheckOwnership(m.GetStringProperty(DesiredAliasKey), Guid.Parse(m.GetStringProperty(AliasTokenKey)), m.ReplyToSession)) { var reply = MessageFactory.CreateAcknowledgment(m); reply.CopyPropertiesFrom(m); Communicator.SendToClientsAsync(reply); Logger.Info($"{m.Identifier} granted ownership of alias '{m.GetStringProperty(DesiredAliasKey)}'"); } else { Logger.Info($"{m.Identifier} denied ownership of alias '{m.GetStringProperty(DesiredAliasKey)}'"); Communicator.SendToClientsAsync(MessageFactory.CreateNegativeAcknowledgment(m, $"Token did not match the one registered for {m.GetStringProperty(DesiredAliasKey)}")); } return(MessageStatus.Complete); }
private async Task InvokeMessageHandlers(IReceiverClient receiver, ApolloQueue queue, ServiceBusMessage message, CancellationToken?token) { if (message == null) { return; } if (Handlers.TryGetValue(queue, out var handlers)) { var status = MessageStatus.Unhandled; foreach (var handler in handlers.Where(h => h.PassesFilter(message))) { try { if (token?.IsCancellationRequested ?? false) { return; } status = handler.HandleMessage(queue, message, token); if (status.HasFlag(MessageStatus.Handled)) { break; } } catch (Exception ex) { Logger.Error($"Encountered an error in {handler.OnMessageReceived.Method.DeclaringType?.Name ?? "<Unknown>"}.{handler.OnMessageReceived.Method.Name} while handling a message labelled {message.Label}", ex); } } if (status.HasFlag(MessageStatus.MarkedForDeletion)) { await receiver.CompleteAsync(message.InnerMessage.SystemProperties.LockToken); } else if (string.IsNullOrWhiteSpace(message.ResponseTo)) { await receiver.DeadLetterAsync(message.InnerMessage.SystemProperties.LockToken, $"{State[ApolloConstants.RegisteredAsKey]} does not have a plugin which can handle this message"); } else { await receiver.DeadLetterAsync(message.InnerMessage.SystemProperties.LockToken, $"{State[ApolloConstants.RegisteredAsKey]} is not expecting or longer waiting for this response"); } } else { Logger.Error($"Received a message on queue {queue} without having any handlers registered for that queue! (This should not be possible and implies that something has gone wrong)"); } }
private MessageStatus AliasOwnershipClaimReceived(ApolloQueue queue, IMessage m, CancellationToken?cancelToken) { var oldOwner = _storage.TakeOwnership(m.GetStringProperty(DesiredAliasKey), Guid.Parse(m.GetStringProperty(AliasTokenKey)), m.ReplyToSession); if (oldOwner != null) { var lostOwnershipMessage = MessageFactory.CreateNewMessage("Lost Alias Ownership"); lostOwnershipMessage.TargetSession = oldOwner; lostOwnershipMessage[DesiredAliasKey] = m.GetStringProperty(DesiredAliasKey); Communicator.SendToClientsAsync(lostOwnershipMessage); } var reply = MessageFactory.CreateAcknowledgment(m); reply.CopyPropertiesFrom(m); Communicator.SendToClientsAsync(reply); return(MessageStatus.Complete); }
private MessageStatus ForwardAliasMessage(ApolloQueue queue, IMessage m, CancellationToken?cancelToken) { var targetAlias = m.GetStringProperty(ApolloConstants.TargetAliasKey); var owner = _storage.GetAliasOwner(targetAlias); if (owner == null) { Communicator.SendToClientsAsync(MessageFactory.CreateNegativeAcknowledgment(m, $"Alias '{targetAlias ?? "<Alias not specified>"}' is not owned or invalid")); } else { var forwardedMessage = MessageFactory.CloneMessage(m); forwardedMessage.TargetSession = owner; Communicator.SendToClientsAsync(forwardedMessage); } return(MessageStatus.Complete); }
public MessageStatus HandleMessage(ApolloQueue queue, IMessage message, CancellationToken?cancelToken) { if (OnMessageReceived == null) { return(MessageStatus.Unhandled); } try { return(OnMessageReceived.Invoke(queue, message, cancelToken)); } catch (Exception ex) { var logger = Plugin?.GetLogger(); logger?.Error($"Encountered an error while processing a message with label {message.Label} ({ex.Message})"); logger?.Debug(ex); OnError?.Invoke(message, ex); throw; } }
protected override string GetQueueName(ApolloQueue queue) { switch (queue) { case ApolloQueue.Registrations: return(Configuration.RegistrationQueue); case ApolloQueue.ServerRequests: return(Configuration.ServerRequestsQueue); case ApolloQueue.Aliases: return(Configuration.ClientAliasesQueue); case ApolloQueue.ClientSessions: return(Configuration.ClientsQueue); default: throw new ArgumentOutOfRangeException(nameof(queue), queue, null); } }
public ConcurrentQueue <MockMessage> GetSessionQueue(ApolloQueue queueType, string identifier) { return(SessionQueues.TryGetValue(queueType, out var queue) ? queue.GetOrAdd(identifier, new ConcurrentQueue <MockMessage>()) : null); }
public MockMessageSender(MockServiceBusQueues queues, ApolloQueue queueType) { QueueType = queueType; Queues = queues; }
private MockQueue GetSessionQueue(ApolloQueue queueType, string identifier) { return(SessionQueues.TryGetValue(queueType, out var queue) ? queue.GetOrAdd(identifier, new MockQueue()) : null); }
public MockQueue GetQueue(ApolloQueue queueType, string targetSession) { return(!NormalQueues.TryGetValue(queueType, out var queue) ? GetSessionQueue(queueType, targetSession) : queue); }