protected void MoveMessageToDlq <T>(IMessage <T> message) { // Move the Message to the DLQ (Also need to delete from the current queue) var messageBody = GetSqsMessageBody(message); Log.DebugFormat("Message {0} has failed {1} times, moving to DLQ.", message.Id, message.RetryAttempts); string dlqName = string.Empty; try { var queueNames = new VersionedQueueNames(messageBody.GetType()); dlqName = queueNames.Dlq; var dlqUrl = this.SqsClient.GetOrCreateQueueUrl(dlqName); // Put in DLQ before deleting, we can't 'lose' the message. this.RepublishFailedMessageToQueue(message, dlqUrl, queueNames.Dlq); // Note: If this 'DeleteMessage' command fails, it does not matter. this.SqsClient.DeleteMessage(messageBody.QueueUrl, messageBody.ReceiptHandle); } catch (Exception ex) { Log.Error(string.Format("An error occurred trying to move the message {0} to the DLQ '{1}'.", message.Id, dlqName), ex); } }
public void OnMessageProcessingFailedDoesNotUpdateMessageVisibilityIfMovingMessageToDlq() { var message = this.CreateNewMessage(); var messageBody = message.GetBody(); var queueNames = new VersionedQueueNames(messageBody.GetType()); var dlqUrl = "http://queue.com/dlq/"; // GetOrCreateQueue // PublishMessage (To DLQ) -> Test that a new MessageId is assigned! // Delete Message this.SqsClient .Setup(x => x.GetOrCreateQueueUrl(queueNames.Dlq)) .Returns(dlqUrl) .Verifiable(); this.SqsClient .Setup(x => x.PublishMessage(dlqUrl, Convert.ToBase64String(message.ToBytes()))) .Returns(new SendMessageResponse()) .Verifiable(); this.SqsClient .Setup(x => x.DeleteMessage(messageBody.QueueUrl, messageBody.ReceiptHandle)) .Verifiable(); this.MessageProcessor.OnMessageProcessingFailed(message, null, true); this.SqsClient.VerifyAll(); // Verify that 'UpdateMessageVisibility' is NOT called. this.SqsClient.Verify(x => x.ChangeMessageVisibility(messageBody.QueueUrl, messageBody.ReceiptHandle, It.IsAny <decimal>()), Times.Never()); }
private string DetermineQueueName(string queueName, byte[] messageBytes) { var messageBodyType = messageBytes.ToMessage(typeof(IMessage)).Body.GetType(); var versionedQueueNames = new VersionedQueueNames(messageBodyType); var queueExt = queueName.Substring(queueName.LastIndexOf('.') + 1).ToLowerInvariant(); switch (queueExt) { case "inq": return(versionedQueueNames.In); case "priorityq": return(versionedQueueNames.Priority); case "outq": return(versionedQueueNames.Out); case "dlq": return(versionedQueueNames.Dlq); default: // It's not a standard queue, should be a custom queue. return(queueName); } }
/* * private string GetQueueName(Type messageType, long priority) * { * // TODO: Use assembly qualified name for versioned queue's? * var stronglyTypedMessage = typeof(Message<>).MakeGenericType(messageType); * var messageInstance = (IMessage)Activator.CreateInstance(stronglyTypedMessage); * messageInstance.Priority = priority; * * // Use reflection to call the extension method * var methods = typeof(MessageExtensions).GetMethods(BindingFlags.Static | BindingFlags.Public).Where(mi => mi.Name == "ToInQueueName"); * * MethodInfo method = null; * foreach (var methodInfo in methods) * { * var paramType = methodInfo.GetParameters()[0].ParameterType; * if (paramType.GetGenericArguments().Count() == 1) * { * // we are looking for Func<TSource, bool>, the other has 3 * method = methodInfo; * } * } * * if (method == null) * { * throw new NullReferenceException("Could not find 'ToInQueueName' extension method."); * } * * // Execute the extension method * method = method.MakeGenericMethod(messageType); * return (string)method.Invoke(messageInstance, new object[] { messageInstance }); * } */ private IList <string> GetNewQueueNames(Type messageType) { // Use reflection to call the extension method var queueNames = typeof(VersionedQueueNames); var properties = queueNames.GetProperties(BindingFlags.Instance | BindingFlags.Public); var newQueueNames = new List <string>(); var queueNamesInstance = new VersionedQueueNames(messageType); foreach (var property in properties) { if (property.PropertyType == typeof(string)) { newQueueNames.Add((string)queueNames.InvokeMember(property.Name, BindingFlags.Public | BindingFlags.Instance | BindingFlags.GetProperty, null, queueNamesInstance, null)); } } return(newQueueNames); }
protected override void PublishMessage <T>(IMessage <T> message) { // TODO: Refactor to reusable method. Also use when sending notification messages? var messageQueueName = new VersionedQueueNames(typeof(T)).In; // message.ToInQueueName(); if (!this.QueueUrls.ContainsKey(messageQueueName)) { throw new InvalidOperationException(string.Format("No queue is registered for the message type {0}.", typeof(T).Name)); } // TODO: If a notification response is required, clients should use the 'MessageQueueClient'. // TODO: Should messaegs from the Producer be auto-configured to be one-way only? // TODO: Need to test DLQ, and write tests to verify all messages are being processed. // TODO: Look at using in-memory for these unit tests message.Options = (int)MessageOption.None; //// Do not send a reply to the out queue. Log.DebugFormat("Publishing message to queue {0}.", messageQueueName); var response = this.SqsClient.PublishMessage( new SendMessageRequest().WithQueueUrl(this.GetQueueNameOrUrl(message)) .WithMessageBody(Convert.ToBase64String(message.ToBytes()))); }
static void Main(string[] args) { log4net.Config.XmlConfigurator.ConfigureAndWatch(new FileInfo("Client.exe.config")); // var Log4Net = log4net.LogManager.GetLogger(typeof(Program)); // For some reason, in a console app you need to set the LogFactory manually! ServiceStack.Logging.LogManager.LogFactory = new ServiceStack.Logging.Log4Net.Log4NetFactory("Client.exe.config"); var Log = LogManager.GetLogger(typeof(Program)); /* * Log.Info("Info"); * Log.Debug("Debug"); * Log.Warn("Warn"); * Log.Error("Error"); * Log.Fatal("Fatal"); */ Log.Info("===== Starting Client ====="); IMessageQueueClient c; AwsSqsMessageQueueClient sqsMessageQueueClient; // var svc = new InMemoryTransientMessageService(); // var svc = new RedisMqServer(new PooledRedisClientManager(new[] { "localhost:6379" })); var svc = MessageServerFactory.CreateMessageService(); // Register the handlers before creating any client objects. using (var messageQueueClient = svc.MessageFactory.CreateMessageQueueClient()) { Log.Info("===== Message Queue Client Started ====="); Log.Info("Type 'EXIT' to close."); // svc.Start(); while (true) { // The MqClient should result in a message in the out q, as the messages are not configured to be one-way messageQueueClient.Publish(new Hello { Text = "This comes from the client" }); // This message should return a response. messageQueueClient.Publish(new Hello3 { Text = "This comes from the client #3" }); Log.Info("Waiting for message response."); var responseQueueName = new VersionedQueueNames(typeof(Hello3Response)).In; // QueueNames<Hello3Response>.In; var response = messageQueueClient.Get(responseQueueName, TimeSpan.FromSeconds(20)); if (response != null) { var obj = response.ToMessage <Hello3Response>().GetBody(); Log.InfoFormat("Message response received: {0}", obj.ResponseText); sqsMessageQueueClient = messageQueueClient as AwsSqsMessageQueueClient; if (sqsMessageQueueClient != null) { sqsMessageQueueClient.DeleteMessageFromQueue(responseQueueName, obj.ReceiptHandle); } Log.InfoFormat("Deleted response message from queue: {0}", obj.QueueName); } else { Log.Info("No message response received."); } // ================== REQ/REPLY MQ =============== var uniqueCallbackQ = "mq:c1" + ":" + Guid.NewGuid().ToString("N"); messageQueueClient.Publish(new Message <Hello4>(new Hello4 { Text = "This comes from the client #4" }) { ReplyTo = uniqueCallbackQ }); Log.Info("Waiting for message response."); var uniqueResponse = messageQueueClient.Get(uniqueCallbackQ, TimeSpan.FromSeconds(20)); if (uniqueResponse != null) { var obj = uniqueResponse.ToMessage <Hello4Response>().GetBody(); Log.InfoFormat("Message response received: {0}", obj.ResponseText); sqsMessageQueueClient = messageQueueClient as AwsSqsMessageQueueClient; if (sqsMessageQueueClient != null) { sqsMessageQueueClient.DeleteMessageFromQueue(uniqueCallbackQ, obj.ReceiptHandle); } Log.InfoFormat("Deleted response message from queue: {0}", obj.QueueName); } else { Log.Info("No message response received."); } // Optionally, delete the mq. sqsMessageQueueClient = messageQueueClient as AwsSqsMessageQueueClient; if (sqsMessageQueueClient != null) { sqsMessageQueueClient.DeleteQueue(uniqueCallbackQ); } // =============================================== // TODO: TEST - messageQueueClient.WaitForNotifyOnAny() var text = Console.ReadLine() ?? string.Empty; if (text.ToUpperInvariant() == "EXIT") { break; } } } Log.Info("Stopping Client."); }
protected override string GetQueueNameOrUrl <T>(IMessage <T> message) { var messageQueueName = new VersionedQueueNames(typeof(T)).In; return(this.QueueUrls[messageQueueName]); }