/// <summary> /// Receives a <see cref="EventData"/> from the event bus. /// </summary> protected virtual void ReceiveEvent(PartitionContext context, EventData eventData) { DateTimeOffset startedAt = DateTimeOffset.UtcNow; Stopwatch mainStopWatch = Stopwatch.StartNew(); string responseCode = "200"; // Null means it was skipped bool?wasSuccessfull = true; #if NET452 string telemetryName = string.Format("Cqrs/Handle/Event/{0}", eventData.SequenceNumber); #endif #if NETSTANDARD2_0 string telemetryName = string.Format("Cqrs/Handle/Event/{0}", eventData.SystemProperties.SequenceNumber); #endif ISingleSignOnToken authenticationToken = null; Guid? guidAuthenticationToken = null; string stringAuthenticationToken = null; int? intAuthenticationToken = null; IDictionary <string, string> telemetryProperties = new Dictionary <string, string> { { "Type", "Azure/EventHub" } }; object value; if (eventData.Properties.TryGetValue("Type", out value)) { telemetryProperties.Add("MessageType", value.ToString()); } TelemetryHelper.TrackMetric("Cqrs/Handle/Event", CurrentHandles++, telemetryProperties); // Do a manual 10 try attempt with back-off for (int i = 0; i < 10; i++) { try { #if NET452 Logger.LogDebug(string.Format("An event message arrived with the partition key '{0}', sequence number '{1}' and offset '{2}'.", eventData.PartitionKey, eventData.SequenceNumber, eventData.Offset)); #endif #if NETSTANDARD2_0 Logger.LogDebug(string.Format("An event message arrived with the partition key '{0}', sequence number '{1}' and offset '{2}'.", eventData.SystemProperties.PartitionKey, eventData.SystemProperties.SequenceNumber, eventData.SystemProperties.Offset)); #endif #if NET452 string messageBody = Encoding.UTF8.GetString(eventData.GetBytes()); #endif #if NETSTANDARD2_0 string messageBody = Encoding.UTF8.GetString(eventData.Body.Array, eventData.Body.Offset, eventData.Body.Count); #endif IEvent <TAuthenticationToken> @event = AzureBusHelper.ReceiveEvent(messageBody, ReceiveEvent, #if NET452 string.Format("partition key '{0}', sequence number '{1}' and offset '{2}'", eventData.PartitionKey, eventData.SequenceNumber, eventData.Offset), #endif #if NETSTANDARD2_0 string.Format("partition key '{0}', sequence number '{1}' and offset '{2}'", eventData.SystemProperties.PartitionKey, eventData.SystemProperties.SequenceNumber, eventData.SystemProperties.Offset), #endif ExtractSignature(eventData), SigningTokenConfigurationKey, () => { wasSuccessfull = null; #if NET452 telemetryName = string.Format("Cqrs/Handle/Event/Skipped/{0}", eventData.SequenceNumber); #endif #if NETSTANDARD2_0 telemetryName = string.Format("Cqrs/Handle/Event/Skipped/{0}", eventData.SystemProperties.SequenceNumber); #endif responseCode = "204"; // Remove message from queue context.CheckpointAsync(eventData); #if NET452 Logger.LogDebug(string.Format("An event message arrived with the partition key '{0}', sequence number '{1}' and offset '{2}' but processing was skipped due to event settings.", eventData.PartitionKey, eventData.SequenceNumber, eventData.Offset)); #endif #if NETSTANDARD2_0 Logger.LogDebug(string.Format("An event message arrived with the partition key '{0}', sequence number '{1}' and offset '{2}' but processing was skipped due to event settings.", eventData.SystemProperties.PartitionKey, eventData.SystemProperties.SequenceNumber, eventData.SystemProperties.Offset)); #endif TelemetryHelper.TrackEvent("Cqrs/Handle/Event/Skipped", telemetryProperties); } ); if (wasSuccessfull != null) { if (@event != null) { telemetryName = string.Format("{0}/{1}/{2}", @event.GetType().FullName, @event.GetIdentity(), @event.Id); authenticationToken = @event.AuthenticationToken as ISingleSignOnToken; if (AuthenticationTokenIsGuid) { guidAuthenticationToken = @event.AuthenticationToken as Guid?; } if (AuthenticationTokenIsString) { stringAuthenticationToken = @event.AuthenticationToken as string; } if (AuthenticationTokenIsInt) { intAuthenticationToken = @event.AuthenticationToken as int?; } var telemeteredMessage = @event as ITelemeteredMessage; if (telemeteredMessage != null) { telemetryName = telemeteredMessage.TelemetryName; } telemetryName = string.Format("Cqrs/Handle/Event/{0}", telemetryName); } // Remove message from queue context.CheckpointAsync(eventData); } #if NET452 Logger.LogDebug(string.Format("An event message arrived and was processed with the partition key '{0}', sequence number '{1}' and offset '{2}'.", eventData.PartitionKey, eventData.SequenceNumber, eventData.Offset)); #endif #if NETSTANDARD2_0 Logger.LogDebug(string.Format("An event message arrived and was processed with the partition key '{0}', sequence number '{1}' and offset '{2}'.", eventData.SystemProperties.PartitionKey, eventData.SystemProperties.SequenceNumber, eventData.SystemProperties.Offset)); #endif IList <IEvent <TAuthenticationToken> > events; if (EventWaits.TryGetValue(@event.CorrelationId, out events)) { events.Add(@event); } wasSuccessfull = true; responseCode = "200"; return; } catch (UnAuthorisedMessageReceivedException exception) { TelemetryHelper.TrackException(exception, null, telemetryProperties); // Indicates a problem, unlock message in queue #if NET452 Logger.LogError(string.Format("An event message arrived with the partition key '{0}', sequence number '{1}' and offset '{2}' but was not authorised.", eventData.PartitionKey, eventData.SequenceNumber, eventData.Offset), exception: exception); #endif #if NETSTANDARD2_0 Logger.LogError(string.Format("An event message arrived with the partition key '{0}', sequence number '{1}' and offset '{2}' but was not authorised.", eventData.SystemProperties.PartitionKey, eventData.SystemProperties.SequenceNumber, eventData.SystemProperties.Offset), exception: exception); #endif wasSuccessfull = false; responseCode = "401"; telemetryProperties.Add("ExceptionType", exception.GetType().FullName); telemetryProperties.Add("ExceptionMessage", exception.Message); } catch (NoHandlersRegisteredException exception) { TelemetryHelper.TrackException(exception, null, telemetryProperties); // Indicates a problem, unlock message in queue #if NET452 Logger.LogError(string.Format("An event message arrived with the partition key '{0}', sequence number '{1}' and offset '{2}' but no handlers were found to process it.", eventData.PartitionKey, eventData.SequenceNumber, eventData.Offset), exception: exception); #endif #if NETSTANDARD2_0 Logger.LogError(string.Format("An event message arrived with the partition key '{0}', sequence number '{1}' and offset '{2}' but no handlers were found to process it.", eventData.SystemProperties.PartitionKey, eventData.SystemProperties.SequenceNumber, eventData.SystemProperties.Offset), exception: exception); #endif wasSuccessfull = false; responseCode = "501"; telemetryProperties.Add("ExceptionType", exception.GetType().FullName); telemetryProperties.Add("ExceptionMessage", exception.Message); } catch (NoHandlerRegisteredException exception) { TelemetryHelper.TrackException(exception, null, telemetryProperties); // Indicates a problem, unlock message in queue #if NET452 Logger.LogError(string.Format("An event message arrived with the partition key '{0}', sequence number '{1}' and offset '{2}'s but no handler was found to process it.", eventData.PartitionKey, eventData.SequenceNumber, eventData.Offset), exception: exception); #endif #if NETSTANDARD2_0 Logger.LogError(string.Format("An event message arrived with the partition key '{0}', sequence number '{1}' and offset '{2}'s but no handler was found to process it.", eventData.SystemProperties.PartitionKey, eventData.SystemProperties.SequenceNumber, eventData.SystemProperties.Offset), exception: exception); #endif wasSuccessfull = false; responseCode = "501"; telemetryProperties.Add("ExceptionType", exception.GetType().FullName); telemetryProperties.Add("ExceptionMessage", exception.Message); } catch (Exception exception) { // Indicates a problem, unlock message in queue #if NET452 Logger.LogError(string.Format("An event message arrived with the partition key '{0}', sequence number '{1}' and offset '{2}' but failed to be process.", eventData.PartitionKey, eventData.SequenceNumber, eventData.Offset), exception: exception); #endif #if NETSTANDARD2_0 Logger.LogError(string.Format("An event message arrived with the partition key '{0}', sequence number '{1}' and offset '{2}' but failed to be process.", eventData.SystemProperties.PartitionKey, eventData.SystemProperties.SequenceNumber, eventData.SystemProperties.Offset), exception: exception); #endif switch (i) { case 0: case 1: // 10 seconds Thread.Sleep(10 * 1000); break; case 2: case 3: // 30 seconds Thread.Sleep(30 * 1000); break; case 4: case 5: case 6: // 1 minute Thread.Sleep(60 * 1000); break; case 7: case 8: // 3 minutes Thread.Sleep(3 * 60 * 1000); break; case 9: telemetryProperties.Add("ExceptionType", exception.GetType().FullName); telemetryProperties.Add("ExceptionMessage", exception.Message); break; } wasSuccessfull = false; responseCode = "500"; } finally { // Eventually just accept it context.CheckpointAsync(eventData); TelemetryHelper.TrackMetric("Cqrs/Handle/Event", CurrentHandles--, telemetryProperties); mainStopWatch.Stop(); if (guidAuthenticationToken != null) { TelemetryHelper.TrackRequest ( telemetryName, guidAuthenticationToken, startedAt, mainStopWatch.Elapsed, responseCode, wasSuccessfull == null || wasSuccessfull.Value, telemetryProperties ); } else if (intAuthenticationToken != null) { TelemetryHelper.TrackRequest ( telemetryName, intAuthenticationToken, startedAt, mainStopWatch.Elapsed, responseCode, wasSuccessfull == null || wasSuccessfull.Value, telemetryProperties ); } else if (stringAuthenticationToken != null) { TelemetryHelper.TrackRequest ( telemetryName, stringAuthenticationToken, startedAt, mainStopWatch.Elapsed, responseCode, wasSuccessfull == null || wasSuccessfull.Value, telemetryProperties ); } else { TelemetryHelper.TrackRequest ( telemetryName, authenticationToken, startedAt, mainStopWatch.Elapsed, responseCode, wasSuccessfull == null || wasSuccessfull.Value, telemetryProperties ); } TelemetryHelper.Flush(); } } }
/// <summary> /// Receives a <see cref="BrokeredMessage"/> from the event bus. /// </summary> protected virtual void ReceiveEvent(BrokeredMessage message) { DateTimeOffset startedAt = DateTimeOffset.UtcNow; Stopwatch mainStopWatch = Stopwatch.StartNew(); string responseCode = "200"; // Null means it was skipped bool? wasSuccessfull = true; string telemetryName = string.Format("Cqrs/Handle/Event/{0}", message.MessageId); ISingleSignOnToken authenticationToken = null; Guid? guidAuthenticationToken = null; string stringAuthenticationToken = null; int?intAuthenticationToken = null; IDictionary <string, string> telemetryProperties = ExtractTelemetryProperties(message, "Azure/Servicebus"); TelemetryHelper.TrackMetric("Cqrs/Handle/Event", CurrentHandles++, telemetryProperties); var brokeredMessageRenewCancellationTokenSource = new CancellationTokenSource(); try { Logger.LogDebug(string.Format("An event message arrived with the id '{0}'.", message.MessageId)); string messageBody = message.GetBody <string>(); IEvent <TAuthenticationToken> @event = AzureBusHelper.ReceiveEvent(messageBody, ReceiveEvent, string.Format("id '{0}'", message.MessageId), ExtractSignature(message), SigningTokenConfigurationKey, () => { wasSuccessfull = null; telemetryName = string.Format("Cqrs/Handle/Event/Skipped/{0}", message.MessageId); responseCode = "204"; // Remove message from queue try { message.Complete(); } catch (MessageLockLostException exception) { throw new MessageLockLostException(string.Format("The lock supplied for the skipped event message '{0}' is invalid.", message.MessageId), exception); } Logger.LogDebug(string.Format("An event message arrived with the id '{0}' but processing was skipped due to event settings.", message.MessageId)); TelemetryHelper.TrackEvent("Cqrs/Handle/Event/Skipped", telemetryProperties); }, () => { AzureBusHelper.RefreshLock(brokeredMessageRenewCancellationTokenSource, message, "event"); } ); if (wasSuccessfull != null) { if (@event != null) { telemetryName = string.Format("{0}/{1}/{2}", @event.GetType().FullName, @event.GetIdentity(), @event.Id); authenticationToken = @event.AuthenticationToken as ISingleSignOnToken; if (AuthenticationTokenIsGuid) { guidAuthenticationToken = @event.AuthenticationToken as Guid?; } if (AuthenticationTokenIsString) { stringAuthenticationToken = @event.AuthenticationToken as string; } if (AuthenticationTokenIsInt) { intAuthenticationToken = @event.AuthenticationToken as int?; } var telemeteredMessage = @event as ITelemeteredMessage; if (telemeteredMessage != null) { telemetryName = telemeteredMessage.TelemetryName; } telemetryName = string.Format("Cqrs/Handle/Event/{0}", telemetryName); } // Remove message from queue try { message.Complete(); } catch (MessageLockLostException exception) { throw new MessageLockLostException(string.Format("The lock supplied for event '{0}' of type {1} is invalid.", @event.Id, @event.GetType().Name), exception); } } Logger.LogDebug(string.Format("An event message arrived and was processed with the id '{0}'.", message.MessageId)); IList <IEvent <TAuthenticationToken> > events; if (EventWaits.TryGetValue(@event.CorrelationId, out events)) { events.Add(@event); } } catch (MessageLockLostException exception) { IDictionary <string, string> subTelemetryProperties = new Dictionary <string, string>(telemetryProperties); subTelemetryProperties.Add("TimeTaken", mainStopWatch.Elapsed.ToString()); TelemetryHelper.TrackException(exception, null, subTelemetryProperties); if (ThrowExceptionOnReceiverMessageLockLostExceptionDuringComplete) { Logger.LogError(exception.Message, exception: exception); // Indicates a problem, unlock message in queue message.Abandon(); wasSuccessfull = false; } else { Logger.LogWarning(exception.Message, exception: exception); try { message.DeadLetter("LockLostButHandled", "The message was handled but the lock was lost."); } catch (Exception) { // Oh well, move on. message.Abandon(); } } responseCode = "599"; } catch (UnAuthorisedMessageReceivedException exception) { TelemetryHelper.TrackException(exception, null, telemetryProperties); // Indicates a problem, unlock message in queue Logger.LogError(string.Format("An event message arrived with the id '{0}' but was not authorised.", message.MessageId), exception: exception); message.DeadLetter("UnAuthorisedMessageReceivedException", exception.Message); wasSuccessfull = false; responseCode = "401"; telemetryProperties.Add("ExceptionType", exception.GetType().FullName); telemetryProperties.Add("ExceptionMessage", exception.Message); } catch (NoHandlersRegisteredException exception) { TelemetryHelper.TrackException(exception, null, telemetryProperties); // Indicates a problem, unlock message in queue Logger.LogError(string.Format("An event message arrived with the id '{0}' but no handlers were found to process it.", message.MessageId), exception: exception); message.DeadLetter("NoHandlersRegisteredException", exception.Message); wasSuccessfull = false; responseCode = "501"; telemetryProperties.Add("ExceptionType", exception.GetType().FullName); telemetryProperties.Add("ExceptionMessage", exception.Message); } catch (NoHandlerRegisteredException exception) { TelemetryHelper.TrackException(exception, null, telemetryProperties); // Indicates a problem, unlock message in queue Logger.LogError(string.Format("An event message arrived with the id '{0}' but no handler was found to process it.", message.MessageId), exception: exception); message.DeadLetter("NoHandlerRegisteredException", exception.Message); wasSuccessfull = false; responseCode = "501"; telemetryProperties.Add("ExceptionType", exception.GetType().FullName); telemetryProperties.Add("ExceptionMessage", exception.Message); } catch (Exception exception) { TelemetryHelper.TrackException(exception, null, telemetryProperties); // Indicates a problem, unlock message in queue Logger.LogError(string.Format("An event message arrived with the id '{0}' but failed to be process.", message.MessageId), exception: exception); message.Abandon(); wasSuccessfull = false; responseCode = "500"; telemetryProperties.Add("ExceptionType", exception.GetType().FullName); telemetryProperties.Add("ExceptionMessage", exception.Message); } finally { // Cancel the lock of renewing the task brokeredMessageRenewCancellationTokenSource.Cancel(); TelemetryHelper.TrackMetric("Cqrs/Handle/Event", CurrentHandles--, telemetryProperties); mainStopWatch.Stop(); if (guidAuthenticationToken != null) { TelemetryHelper.TrackRequest ( telemetryName, guidAuthenticationToken, startedAt, mainStopWatch.Elapsed, responseCode, wasSuccessfull == null || wasSuccessfull.Value, telemetryProperties ); } else if (intAuthenticationToken != null) { TelemetryHelper.TrackRequest ( telemetryName, intAuthenticationToken, startedAt, mainStopWatch.Elapsed, responseCode, wasSuccessfull == null || wasSuccessfull.Value, telemetryProperties ); } else if (stringAuthenticationToken != null) { TelemetryHelper.TrackRequest ( telemetryName, stringAuthenticationToken, startedAt, mainStopWatch.Elapsed, responseCode, wasSuccessfull == null || wasSuccessfull.Value, telemetryProperties ); } else { TelemetryHelper.TrackRequest ( telemetryName, authenticationToken, startedAt, mainStopWatch.Elapsed, responseCode, wasSuccessfull == null || wasSuccessfull.Value, telemetryProperties ); } TelemetryHelper.Flush(); } }
protected virtual void ReceiveEvent(BrokeredMessage message) { DateTimeOffset startedAt = DateTimeOffset.UtcNow; Stopwatch mainStopWatch = Stopwatch.StartNew(); string responseCode = "200"; // Null means it was skipped bool? wasSuccessfull = true; string telemetryName = string.Format("Cqrs/Handle/Event/{0}", message.MessageId); ISingleSignOnToken authenticationToken = null; IDictionary <string, string> telemetryProperties = new Dictionary <string, string> { { "Type", "Azure/Servicebus" } }; object value; if (message.Properties.TryGetValue("Type", out value)) { telemetryProperties.Add("MessageType", value.ToString()); } TelemetryHelper.TrackMetric("Cqrs/Handle/Event", CurrentHandles++, telemetryProperties); var brokeredMessageRenewCancellationTokenSource = new CancellationTokenSource(); try { Logger.LogDebug(string.Format("An event message arrived with the id '{0}'.", message.MessageId)); string messageBody = message.GetBody <string>(); IEvent <TAuthenticationToken> @event = AzureBusHelper.ReceiveEvent(messageBody, ReceiveEvent, string.Format("id '{0}'", message.MessageId), () => { wasSuccessfull = null; telemetryName = string.Format("Cqrs/Handle/Event/Skipped/{0}", message.MessageId); responseCode = "204"; // Remove message from queue try { message.Complete(); } catch (MessageLockLostException exception) { throw new MessageLockLostException(string.Format("The lock supplied for the skipped event message '{0}' is invalid.", message.MessageId), exception); } Logger.LogDebug(string.Format("An event message arrived with the id '{0}' but processing was skipped due to event settings.", message.MessageId)); TelemetryHelper.TrackEvent("Cqrs/Handle/Event/Skipped", telemetryProperties); }, () => { AzureBusHelper.RefreshLock(brokeredMessageRenewCancellationTokenSource, message, "event"); } ); if (wasSuccessfull != null) { if (@event != null) { telemetryName = string.Format("{0}/{1}", @event.GetType().FullName, @event.Id); authenticationToken = @event.AuthenticationToken as ISingleSignOnToken; var telemeteredMessage = @event as ITelemeteredMessage; if (telemeteredMessage != null) { telemetryName = telemeteredMessage.TelemetryName; } telemetryName = string.Format("Cqrs/Handle/Event/{0}", telemetryName); } // Remove message from queue try { message.Complete(); } catch (MessageLockLostException exception) { throw new MessageLockLostException(string.Format("The lock supplied for event '{0}' of type {1} is invalid.", @event.Id, @event.GetType().Name), exception); } } Logger.LogDebug(string.Format("An event message arrived and was processed with the id '{0}'.", message.MessageId)); IList <IEvent <TAuthenticationToken> > events; if (EventWaits.TryGetValue(@event.CorrelationId, out events)) { events.Add(@event); } } catch (Exception exception) { TelemetryHelper.TrackException(exception, null, telemetryProperties); // Indicates a problem, unlock message in queue Logger.LogError(string.Format("An event message arrived with the id '{0}' but failed to be process.", message.MessageId), exception: exception); message.Abandon(); wasSuccessfull = false; responseCode = "500"; } finally { // Cancel the lock of renewing the task brokeredMessageRenewCancellationTokenSource.Cancel(); TelemetryHelper.TrackMetric("Cqrs/Handle/Event", CurrentHandles--, telemetryProperties); mainStopWatch.Stop(); TelemetryHelper.TrackRequest ( telemetryName, authenticationToken, startedAt, mainStopWatch.Elapsed, responseCode, wasSuccessfull == null || wasSuccessfull.Value, telemetryProperties ); TelemetryHelper.Flush(); } }
protected virtual void ReceiveEvent(PartitionContext context, EventData eventData) { DateTimeOffset startedAt = DateTimeOffset.UtcNow; Stopwatch mainStopWatch = Stopwatch.StartNew(); string responseCode = "200"; // Null means it was skipped bool? wasSuccessfull = true; string telemetryName = string.Format("Cqrs/Handle/Event/{0}", eventData.SequenceNumber); ISingleSignOnToken authenticationToken = null; IDictionary <string, string> telemetryProperties = new Dictionary <string, string> { { "Type", "Azure/EventHub" } }; object value; if (eventData.Properties.TryGetValue("Type", out value)) { telemetryProperties.Add("MessageType", value.ToString()); } TelemetryHelper.TrackMetric("Cqrs/Handle/Event", CurrentHandles++, telemetryProperties); // Do a manual 10 try attempt with back-off for (int i = 0; i < 10; i++) { try { Logger.LogDebug(string.Format("An event message arrived with the partition key '{0}', sequence number '{1}' and offset '{2}'.", eventData.PartitionKey, eventData.SequenceNumber, eventData.Offset)); string messageBody = Encoding.UTF8.GetString(eventData.GetBytes()); IEvent <TAuthenticationToken> @event = AzureBusHelper.ReceiveEvent(messageBody, ReceiveEvent, string.Format("partition key '{0}', sequence number '{1}' and offset '{2}'", eventData.PartitionKey, eventData.SequenceNumber, eventData.Offset), () => { wasSuccessfull = null; telemetryName = string.Format("Cqrs/Handle/Event/Skipped/{0}", eventData.SequenceNumber); responseCode = "204"; // Remove message from queue context.CheckpointAsync(eventData); Logger.LogDebug(string.Format("An event message arrived with the partition key '{0}', sequence number '{1}' and offset '{2}' but processing was skipped due to event settings.", eventData.PartitionKey, eventData.SequenceNumber, eventData.Offset)); TelemetryHelper.TrackEvent("Cqrs/Handle/Event/Skipped", telemetryProperties); } ); if (wasSuccessfull != null) { if (@event != null) { telemetryName = string.Format("{0}/{1}", @event.GetType().FullName, @event.Id); authenticationToken = @event.AuthenticationToken as ISingleSignOnToken; var telemeteredMessage = @event as ITelemeteredMessage; if (telemeteredMessage != null) { telemetryName = telemeteredMessage.TelemetryName; } telemetryName = string.Format("Cqrs/Handle/Event/{0}", telemetryName); } // Remove message from queue context.CheckpointAsync(eventData); } Logger.LogDebug(string.Format("An event message arrived and was processed with the partition key '{0}', sequence number '{1}' and offset '{2}'.", eventData.PartitionKey, eventData.SequenceNumber, eventData.Offset)); IList <IEvent <TAuthenticationToken> > events; if (EventWaits.TryGetValue(@event.CorrelationId, out events)) { events.Add(@event); } wasSuccessfull = true; responseCode = "200"; return; } catch (Exception exception) { // Indicates a problem, unlock message in queue Logger.LogError(string.Format("An event message arrived with the partition key '{0}', sequence number '{1}' and offset '{2}' but failed to be process.", eventData.PartitionKey, eventData.SequenceNumber, eventData.Offset), exception: exception); switch (i) { case 0: case 1: // 10 seconds Thread.Sleep(10 * 1000); break; case 2: case 3: // 30 seconds Thread.Sleep(30 * 1000); break; case 4: case 5: case 6: // 1 minute Thread.Sleep(60 * 1000); break; case 7: case 8: // 3 minutes Thread.Sleep(3 * 60 * 1000); break; case 9: telemetryProperties.Add("ExceptionType", exception.GetType().FullName); telemetryProperties.Add("ExceptionMessage", exception.Message); break; } wasSuccessfull = false; responseCode = "500"; } finally { // Eventually just accept it context.CheckpointAsync(eventData); TelemetryHelper.TrackMetric("Cqrs/Handle/Event", CurrentHandles--, telemetryProperties); mainStopWatch.Stop(); TelemetryHelper.TrackRequest ( telemetryName, authenticationToken, startedAt, mainStopWatch.Elapsed, responseCode, wasSuccessfull == null || wasSuccessfull.Value, telemetryProperties ); TelemetryHelper.Flush(); } } }
protected virtual void ReceiveEvent(BrokeredMessage message) { var brokeredMessageRenewCancellationTokenSource = new CancellationTokenSource(); try { Logger.LogDebug(string.Format("An event message arrived with the id '{0}'.", message.MessageId)); string messageBody = message.GetBody <string>(); IEvent <TAuthenticationToken> @event = AzureBusHelper.ReceiveEvent(messageBody, ReceiveEvent, string.Format("id '{0}'", message.MessageId), () => { // Remove message from queue message.Complete(); Logger.LogDebug(string.Format("An event message arrived with the id '{0}' but processing was skipped due to event settings.", message.MessageId)); }, () => { Task.Factory.StartNewSafely(() => { long loop = long.MinValue; while (!brokeredMessageRenewCancellationTokenSource.Token.IsCancellationRequested) { //Based on LockedUntilUtc property to determine if the lock expires soon if (DateTime.UtcNow > message.LockedUntilUtc.AddSeconds(-10)) { // If so, renew the lock for (int i = 0; i < 10; i++) { try { message.RenewLock(); break; } catch { } } } if (loop++ % 5 == 0) { Thread.Yield(); } else { Thread.Sleep(500); } if (loop == long.MaxValue) { loop = long.MinValue; } } brokeredMessageRenewCancellationTokenSource.Dispose(); }, brokeredMessageRenewCancellationTokenSource.Token); } ); // Remove message from queue message.Complete(); Logger.LogDebug(string.Format("An event message arrived and was processed with the id '{0}'.", message.MessageId)); IList <IEvent <TAuthenticationToken> > events; if (EventWaits.TryGetValue(@event.CorrelationId, out events)) { events.Add(@event); } } catch (Exception exception) { // Indicates a problem, unlock message in queue Logger.LogError(string.Format("An event message arrived with the id '{0}' but failed to be process.", message.MessageId), exception: exception); message.Abandon(); } finally { // Cancel the lock of renewing the task brokeredMessageRenewCancellationTokenSource.Cancel(); } }
/// <summary> /// Publishes the provided <paramref name="event"/> on the event bus. /// </summary> public virtual void Publish <TEvent>(TEvent @event) where TEvent : IEvent <TAuthenticationToken> { Type eventType = @event.GetType(); string eventName = eventType.FullName; ISagaEvent <TAuthenticationToken> sagaEvent = @event as ISagaEvent <TAuthenticationToken>; if (sagaEvent != null) { eventName = string.Format("Cqrs.Events.SagaEvent[{0}]", sagaEvent.Event.GetType().FullName); } DateTimeOffset startedAt = DateTimeOffset.UtcNow; Stopwatch mainStopWatch = Stopwatch.StartNew(); string responseCode = "200"; bool wasSuccessfull = false; IDictionary <string, string> telemetryProperties = new Dictionary <string, string> { { "Type", "InProcessBus" } }; string telemetryName = string.Format("{0}/{1}/{2}", eventName, @event.GetIdentity(), @event.Id); var telemeteredEvent = @event as ITelemeteredMessage; if (telemeteredEvent != null) { telemetryName = telemeteredEvent.TelemetryName; } telemetryName = string.Format("Event/{0}", telemetryName); try { if (@event.Frameworks != null && @event.Frameworks.Contains("Built-In")) { Logger.LogInfo("The provided event has already been processed by the Built-In bus.", string.Format("{0}\\PrepareAndValidateEvent({1})", GetType().FullName, eventType.FullName)); return; } if (@event.AuthenticationToken == null || @event.AuthenticationToken.Equals(default(TAuthenticationToken))) { @event.AuthenticationToken = AuthenticationTokenHelper.GetAuthenticationToken(); } @event.CorrelationId = CorrelationIdHelper.GetCorrelationId(); if (string.IsNullOrWhiteSpace(@event.OriginatingFramework)) { @event.TimeStamp = DateTimeOffset.UtcNow; @event.OriginatingFramework = "Built-In"; } var frameworks = new List <string>(); if (@event.Frameworks != null) { frameworks.AddRange(@event.Frameworks); } frameworks.Add("Built-In"); @event.Frameworks = frameworks; bool isRequired; if (!ConfigurationManager.TryGetSetting(string.Format("{0}.IsRequired", eventName), out isRequired)) { isRequired = true; } IEnumerable <Action <IMessage> > handlers = Routes.GetHandlers(@event, isRequired).Select(x => x.Delegate).ToList(); // This check doesn't require an isRequired check as there will be an exception raised above and handled below. if (!handlers.Any()) { Logger.LogDebug(string.Format("An event handler for '{0}' is not required.", eventName)); } foreach (Action <IMessage> handler in handlers) { IList <IEvent <TAuthenticationToken> > events; if (EventWaits.TryGetValue(@event.CorrelationId, out events)) { events.Add(@event); } handler(@event); } Logger.LogInfo(string.Format("An event was sent of type {0}.", eventName)); wasSuccessfull = true; } catch (Exception exception) { responseCode = "500"; Logger.LogError("An issue occurred while trying to publish an event.", exception: exception, metaData: new Dictionary <string, object> { { "Event", @event } }); throw; } finally { mainStopWatch.Stop(); TelemetryHelper.TrackDependency("InProcessBus/EventBus", "Event", telemetryName, null, startedAt, mainStopWatch.Elapsed, responseCode, wasSuccessfull, telemetryProperties); } }
protected virtual void ReceiveEvent(PartitionContext context, EventData eventData) { IDictionary <string, string> telemetryProperties = new Dictionary <string, string> { { "Type", "Azure/EventHub" } }; TelemetryHelper.TrackMetric("Cqrs/Handle/Event", CurrentHandles++, telemetryProperties); // Do a manual 10 try attempt with back-off for (int i = 0; i < 10; i++) { try { Logger.LogDebug(string.Format("An event message arrived with the partition key '{0}', sequence number '{1}' and offset '{2}'.", eventData.PartitionKey, eventData.SequenceNumber, eventData.Offset)); string messageBody = Encoding.UTF8.GetString(eventData.GetBytes()); IEvent <TAuthenticationToken> @event = AzureBusHelper.ReceiveEvent(messageBody, ReceiveEvent, string.Format("partition key '{0}', sequence number '{1}' and offset '{2}'", eventData.PartitionKey, eventData.SequenceNumber, eventData.Offset), () => { // Remove message from queue context.CheckpointAsync(eventData); Logger.LogDebug(string.Format("An event message arrived with the partition key '{0}', sequence number '{1}' and offset '{2}' but processing was skipped due to event settings.", eventData.PartitionKey, eventData.SequenceNumber, eventData.Offset)); } ); // Remove message from queue context.CheckpointAsync(eventData); Logger.LogDebug(string.Format("An event message arrived and was processed with the partition key '{0}', sequence number '{1}' and offset '{2}'.", eventData.PartitionKey, eventData.SequenceNumber, eventData.Offset)); IList <IEvent <TAuthenticationToken> > events; if (EventWaits.TryGetValue(@event.CorrelationId, out events)) { events.Add(@event); } return; } catch (Exception exception) { // Indicates a problem, unlock message in queue Logger.LogError(string.Format("An event message arrived with the partition key '{0}', sequence number '{1}' and offset '{2}' but failed to be process.", eventData.PartitionKey, eventData.SequenceNumber, eventData.Offset), exception: exception); switch (i) { case 0: case 1: // 10 seconds Thread.Sleep(10 * 1000); break; case 2: case 3: // 30 seconds Thread.Sleep(30 * 1000); break; case 4: case 5: case 6: // 1 minute Thread.Sleep(60 * 1000); break; case 7: case 8: case 9: // 3 minutes Thread.Sleep(3 * 60 * 1000); break; } } } // Eventually just accept it context.CheckpointAsync(eventData); TelemetryHelper.TrackMetric("Cqrs/Handle/Event", CurrentHandles--, telemetryProperties); }
protected virtual void ReceiveEvent(BrokeredMessage message) { var brokeredMessageRenewCancellationTokenSource = new CancellationTokenSource(); try { Logger.LogDebug(string.Format("An event message arrived with the id '{0}'.", message.MessageId)); string messageBody = message.GetBody <string>(); IEvent <TAuthenticationToken> @event; try { @event = MessageSerialiser.DeserialiseEvent(messageBody); } catch (JsonSerializationException exception) { JsonSerializationException checkException = exception; bool safeToExit = false; do { if (checkException.Message.StartsWith("Could not load assembly")) { safeToExit = true; break; } } while ((checkException = checkException.InnerException as JsonSerializationException) != null); if (safeToExit) { const string pattern = @"(?<=^Error resolving type specified in JSON ').+?(?='\. Path '\$type')"; Match match = new Regex(pattern).Match(exception.Message); if (match.Success) { string[] typeParts = match.Value.Split(','); if (typeParts.Length == 2) { string classType = typeParts[0]; bool isRequired = BusHelper.IsEventRequired(classType); if (!isRequired) { // Remove message from queue message.Complete(); Logger.LogDebug(string.Format("An event message arrived with the id '{0}' but processing was skipped due to event settings.", message.MessageId)); return; } } } } throw; } CorrelationIdHelper.SetCorrelationId(@event.CorrelationId); Logger.LogInfo(string.Format("An event message arrived with the id '{0}' was of type {1}.", message.MessageId, @event.GetType().FullName)); bool canRefresh; if (!ConfigurationManager.TryGetSetting(string.Format("{0}.ShouldRefresh", @event.GetType().FullName), out canRefresh)) { canRefresh = false; } if (canRefresh) { Task.Factory.StartNew(() => { while (!brokeredMessageRenewCancellationTokenSource.Token.IsCancellationRequested) { //Based on LockedUntilUtc property to determine if the lock expires soon if (DateTime.UtcNow > message.LockedUntilUtc.AddSeconds(-10)) { // If so, repeat the message message.RenewLock(); } Thread.Sleep(500); } }, brokeredMessageRenewCancellationTokenSource.Token); } ReceiveEvent(@event); // Remove message from queue message.Complete(); Logger.LogDebug(string.Format("An event message arrived and was processed with the id '{0}'.", message.MessageId)); IList <IEvent <TAuthenticationToken> > events; if (EventWaits.TryGetValue(@event.CorrelationId, out events)) { events.Add(@event); } } catch (Exception exception) { // Indicates a problem, unlock message in queue Logger.LogError(string.Format("An event message arrived with the id '{0}' but failed to be process.", message.MessageId), exception: exception); message.Abandon(); } finally { // Cancel the lock of renewing the task brokeredMessageRenewCancellationTokenSource.Cancel(); } }