public void SendMessage(Message msg) { if (msg is null) { throw new ArgumentNullException("msg", "Can't send a null message."); } if (stopped) { logger.LogInformation((int)ErrorCode.Runtime_Error_100115, "Message was queued for sending after outbound queue was stopped: {Message}", msg); messageCenter.SendRejection(msg, Message.RejectionTypes.Unrecoverable, "Message was queued for sending after outbound queue was stopped"); return; } // Don't process messages that have already timed out if (msg.IsExpired) { this.messagingTrace.OnDropExpiredMessage(msg, MessagingStatisticsGroup.Phase.Send); return; } // First check to see if it's really destined for a proxied client, instead of a local grain. if (messageCenter.TryDeliverToProxy(msg)) { // Message was successfully delivered to the proxy. return; } if (msg.TargetSilo == null) { logger.LogError((int)ErrorCode.Runtime_Error_100113, "Message does not have a target silo: " + msg + " -- Call stack is: " + Utils.GetStackTrace()); messageCenter.SendRejection(msg, Message.RejectionTypes.Unrecoverable, "Message to be sent does not have a target silo"); return; } messagingTrace.OnSendMessage(msg); if (!messageCenter.TrySendLocal(msg)) { if (stopped) { logger.LogInformation((int)ErrorCode.Runtime_Error_100115, "Message was queued for sending after outbound queue was stopped: {Message}", msg); messageCenter.SendRejection(msg, Message.RejectionTypes.Unrecoverable, "Message was queued for sending after outbound queue was stopped"); return; } // check for simulation of lost messages if (messageCenter.ShouldDrop?.Invoke(msg) == true) { logger.LogInformation((int)ErrorCode.Messaging_SimulatedMessageLoss, "Message blocked by test"); messageCenter.SendRejection(msg, Message.RejectionTypes.Unrecoverable, "Message blocked by test"); return; } if (this.connectionManager.TryGetConnection(msg.TargetSilo, out var existingConnection)) { existingConnection.Send(msg); return; } else if (this.siloStatusOracle.IsDeadSilo(msg.TargetSilo)) { // Do not try to establish this.messagingTrace.OnRejectSendMessageToDeadSilo(this.messageCenter.MyAddress, msg); this.messageCenter.SendRejection(msg, Message.RejectionTypes.Transient, "Target silo is known to be dead"); return; } else { var senderTask = this.connectionManager.GetConnection(msg.TargetSilo); if (senderTask.IsCompletedSuccessfully) { var sender = senderTask.Result; sender.Send(msg); } else { _ = SendAsync(senderTask, msg); async Task SendAsync(ValueTask <Connection> c, Message m) { try { var sender = await c; sender.Send(m); } catch (Exception exception) { this.messageCenter.SendRejection(m, Message.RejectionTypes.Transient, $"Exception while sending message: {exception}"); } } } } } }
public void SendMessage(Message msg) { if (msg == null) { throw new ArgumentNullException("msg", "Can't send a null message."); } if (stopped) { logger.Info(ErrorCode.Runtime_Error_100112, "Message was queued for sending after outbound queue was stopped: {0}", msg); return; } // Don't process messages that have already timed out if (msg.IsExpired) { this.messagingTrace.OnDropExpiredMessage(msg, MessagingStatisticsGroup.Phase.Send); return; } if (!msg.QueuedTime.HasValue) { msg.QueuedTime = DateTime.UtcNow; } // First check to see if it's really destined for a proxied client, instead of a local grain. if (messageCenter.IsProxying && messageCenter.TryDeliverToProxy(msg)) { return; } if (msg.TargetSilo == null) { logger.Error(ErrorCode.Runtime_Error_100113, "Message does not have a target silo: " + msg + " -- Call stack is: " + Utils.GetStackTrace()); messageCenter.SendRejection(msg, Message.RejectionTypes.Unrecoverable, "Message to be sent does not have a target silo"); return; } messagingTrace.OnSendMessage(msg); if (!messageCenter.TrySendLocal(msg)) { if (stopped) { logger.Info(ErrorCode.Runtime_Error_100115, "Message was queued for sending after outbound queue was stopped: {0}", msg); return; } // check for simulation of lost messages if (messageCenter.ShouldDrop?.Invoke(msg) == true) { logger.Info(ErrorCode.Messaging_SimulatedMessageLoss, "Message blocked by test"); messageCenter.SendRejection(msg, Message.RejectionTypes.Unrecoverable, "Message blocked by test"); return; } if (this.siloStatusOracle.IsDeadSilo(msg.TargetSilo)) { MessagingStatisticsGroup.OnFailedSentMessage(msg); var reason = $"Target {msg.TargetSilo.ToLongString()} silo is known to be dead"; if (logger.IsEnabled(LogLevel.Debug)) { logger.LogDebug( (int)ErrorCode.MessagingSendingRejection, "Silo {siloAddress} is rejecting message: {message}. Reason = {reason}", messageCenter.MyAddress, msg, reason); } this.messageCenter.SendRejection(msg, Message.RejectionTypes.Transient, reason); return; } var senderTask = this.connectionManager.GetConnection(msg.TargetSilo); if (senderTask.IsCompletedSuccessfully) { var sender = senderTask.Result; sender.Send(msg); } else { _ = SendAsync(senderTask, msg); async Task SendAsync(ValueTask <Connection> c, Message m) { try { var sender = await c; sender.Send(m); } catch (Exception exception) { this.messageCenter.SendRejection(m, Message.RejectionTypes.Transient, $"Exception while sending message: {exception}"); } } } } }