protected async Task OnMessageCallbackAsync(IReceiverLink receiver, Message message) { var messageTypeName = message.ApplicationProperties[Constants.MESSAGE_TYPE_KEY] as string; var properties = new Dictionary <string, object> { ["CorrelationId"] = message.Properties.CorrelationId, ["MessageId"] = message.Properties.MessageId, ["MessageType"] = messageTypeName }; // if message has correlationId, set it so that handling can be found by initial correlation if (!string.IsNullOrWhiteSpace(message.Properties.CorrelationId)) { CorrelationContext.SetCorrelationId(message.Properties.CorrelationId); } var timer = new Stopwatch(); timer.Start(); using (Logger.BeginScope(properties)) { Logger.LogInformation($"Received message {message.Properties.MessageId}"); try { string body = DomainEventMessage.GetBody(message); Logger.LogTrace("Received message {MessageId} with body: {MessageBody}", message.Properties.MessageId, body); Logger.LogDebug($"Event type key: {messageTypeName}"); if (!EventTypeLookup.ContainsKey(messageTypeName)) { Logger.LogError($"Message {message.Properties.MessageId} rejected because message type was not registered for type {messageTypeName}"); receiver.Reject(message); return; } var dataType = EventTypeLookup[messageTypeName]; Logger.LogDebug($"Event type: {dataType}"); var handlerType = typeof(IDomainEventHandler <>).MakeGenericType(dataType); Logger.LogDebug($"Event type handler interface: {handlerType}"); var handler = Provider.GetService(handlerType); if (handler == null) { Logger.LogError($"Message {message.Properties.MessageId} rejected because handler was not found for type {messageTypeName}"); receiver.Reject(message); return; } Logger.LogDebug($"Event type handler: {handler.GetType()}"); dynamic domainEvent; try { domainEvent = DomainEventMessage.CreateGenericInstance(dataType, message); Logger.LogDebug($"Successfully deserialized body to {dataType}"); } catch (Exception ex) { Logger.LogError(ex, ex.Message); receiver.Reject(message); return; } HandlerResult result; dynamic dhandler = handler; try { result = await dhandler.HandleAsync(domainEvent).ConfigureAwait(false); } catch (Exception ex) { Logger.LogError(ex, $"Message {message.Properties.MessageId} caught unhandled exception {ex.Message}"); result = HandlerResult.Failed; } timer.Stop(); var duration = timer.ElapsedMilliseconds; var dp = new Dictionary <string, object> { ["duration"] = duration }; using (Logger.BeginScope(dp)) { Logger.LogInformation($"Handler executed for message {message.Properties.MessageId} and returned result of {result}"); switch (result) { case HandlerResult.Success: receiver.Accept(message); Logger.LogInformation($"Message {message.Properties.MessageId} accepted"); break; case HandlerResult.Retry: var deliveryCount = message.Header.DeliveryCount; var delay = 10 * deliveryCount; var scheduleTime = DateTime.UtcNow.AddSeconds(delay); using (var ts = new TransactionScope()) { var sender = new SenderLink(Link.Session, Settings.AppName + "-retry", Settings.Queue); // create a new message to be queued with scheduled delivery time var retry = new Message(body) { Header = message.Header, Footer = message.Footer, Properties = message.Properties, ApplicationProperties = message.ApplicationProperties }; retry.ApplicationProperties[Constants.SCHEDULED_ENQUEUE_TIME_UTC] = scheduleTime; sender.Send(retry); receiver.Accept(message); } Logger.LogInformation($"Message {message.Properties.MessageId} requeued with delay of {delay} seconds for {scheduleTime}"); break; case HandlerResult.Failed: receiver.Reject(message); break; case HandlerResult.Release: receiver.Release(message); break; default: throw new NotImplementedException($"Unknown HandlerResult value of {result}"); } } } catch (Exception ex) { timer.Stop(); var duration = timer.ElapsedMilliseconds; var dp = new Dictionary <string, object> { ["duration"] = duration }; using (Logger.BeginScope(dp)) { Logger.LogError(ex, $"Message {message.Properties.MessageId} rejected because of unhandled exception {ex.Message}"); receiver.Reject(message); } } } }
public void Release() { link.Release(message); }