public async Task PublishAsync <T>(T input, string topic, TimeSpan?initialVisibilityDelay = null) where T : class { var newContext = new AFBusMessageContext(); newContext.MessageID = Guid.NewGuid(); newContext.TransactionID = Context.TransactionID ?? Guid.NewGuid(); newContext.BodyType = typeof(T).AssemblyQualifiedName; newContext.BodyInFile = false; newContext.Destination = topic; newContext.SenderServiceName = Context.ActualServiceName; if (initialVisibilityDelay != null) { newContext.MessageDelayedTime = initialVisibilityDelay; newContext.MessageFinalWakeUpTimeStamp = DateTime.UtcNow + initialVisibilityDelay; } else { newContext.MessageDelayedTime = null; newContext.MessageFinalWakeUpTimeStamp = null; } await publisher.PublishEventsAsync(input, topic, newContext).ConfigureAwait(false); }
private async Task InvokeStatelessHandlers <T>(T message, AFBusMessageContext messageContext, ILogger log) where T : class { //The message can not be executed in a stateless handler if (!messageHandlersDictionary.ContainsKey(message.GetType())) { return; } var handlerTypeList = messageHandlersDictionary[message.GetType()]; foreach (var t in handlerTypeList) { var handler = CreateInstance(t); var bus = new Bus(serializer, SolveDependency <ISendMessages>(), SolveDependency <IPublishEvents>()) { Context = messageContext }; object[] parametersArray = new object[] { bus, message, log }; var methodsToInvoke = t.GetMethods().Where(m => m.GetParameters().Any(p => p.ParameterType == message.GetType())); foreach (var m in methodsToInvoke) { log?.LogInformation("Invoke stateless handler " + t.ToString() + " for transaction " + messageContext.TransactionID); await((Task)m.Invoke(handler, parametersArray)).ConfigureAwait(false); } } }
public async Task PublishEventsAsync <T>(T message, string topicName, AFBusMessageContext messageContext) where T : class { var connectionStringBuilder = new EventHubsConnectionStringBuilder(SettingsUtil.GetSettings <string>(SETTINGS.AZURE_EVENTHUB)) { EntityPath = topicName }; var eventHubClient = EventHubClient.CreateFromConnectionString(connectionStringBuilder.ToString()); CloudStorageAccount storageAccount = CloudStorageAccount.Parse(SettingsUtil.GetSettings <string>(SETTINGS.AZURE_STORAGE)); try { var messageAsString = serializer.Serialize(message); var messageWithEnvelope = new AFBusMessageEnvelope() { Context = messageContext, Body = messageAsString }; messageContext.Destination = topicName; var finalMessage = serializer.Serialize(messageWithEnvelope); //if the message is bigger than the limit put the body in the blob storage if ((finalMessage.Length * sizeof(Char)) > MAX_MESSAGE_SIZE) { var fileName = Guid.NewGuid().ToString("N").ToLower() + ".afbus"; messageWithEnvelope.Context.BodyInFile = true; CloudBlobClient cloudBlobClient = storageAccount.CreateCloudBlobClient(); // Create a container var cloudBlobContainer = cloudBlobClient.GetContainerReference(CONTAINER_NAME.ToLower()); await cloudBlobContainer.CreateIfNotExistsAsync().ConfigureAwait(false); CloudBlockBlob blockBlob = cloudBlobContainer.GetBlockBlobReference(fileName); await blockBlob.UploadTextAsync(messageWithEnvelope.Body); messageWithEnvelope.Body = fileName; finalMessage = serializer.Serialize(messageWithEnvelope); } await eventHubClient.SendAsync(new EventData(Encoding.UTF8.GetBytes(finalMessage))); } finally { await eventHubClient.CloseAsync(); } }
public static async Task PublishAsync <T>(T input, string topic, ISerializeMessages serializer = null, IPublishEvents publisher = null) where T : class { serializer = serializer ?? new JSONSerializer(); var newContext = new AFBusMessageContext { MessageID = Guid.NewGuid(), TransactionID = Guid.NewGuid(), BodyType = typeof(T).AssemblyQualifiedName }; publisher = publisher ?? new AzureEventHubPublishTransport(serializer); await publisher.PublishEventsAsync(input, topic, newContext).ConfigureAwait(false); }
private async Task InvokeSagaHandlers <T>(T message, AFBusMessageContext messageContext, ILogger log) where T : class { //The message can not be executed in a Saga if (!messageToSagaDictionary.ContainsKey(message.GetType())) { return; } var instantiated = await LookForCommandsProcessedByASaga(message, messageContext, log).ConfigureAwait(false); instantiated = instantiated || await LookForEventsProcessedBySagas(message, messageContext, log).ConfigureAwait(false); if (!instantiated) { log?.LogInformation("Saga not found for message " + serializer.Serialize(message) + " for transaction " + messageContext.TransactionID); } }
/// <summary> /// Sends a message to a queue named like the service. /// </summary> public static async Task SendAsync <T>(T input, string serviceName, TimeSpan?initialVisibilityDelay = null, ISerializeMessages serializer = null, ISendMessages sender = null) where T : class { serializer = serializer ?? new JSONSerializer(); sender = sender ?? new AzureStorageQueueSendTransport(serializer); var context = new AFBusMessageContext { MessageID = Guid.NewGuid(), TransactionID = Guid.NewGuid(), BodyType = typeof(T).AssemblyQualifiedName }; if (initialVisibilityDelay != null) { context.MessageDelayedTime = initialVisibilityDelay.Value; context.MessageFinalWakeUpTimeStamp = DateTime.UtcNow + initialVisibilityDelay; } await sender.SendMessageAsync(input, serviceName, context).ConfigureAwait(false); }
/// <summary> /// Calls each function referenced by each message in the dictionary. /// </summary> public async Task HandleAsync <T>(T message, ILogger log) where T : class { if (message.GetType() == typeof(AFBusMessageEnvelope)) { throw new Exception("AFBusMessageEnvelope type not permited"); } if (!messageHandlersDictionary.ContainsKey(message.GetType()) && !messageToSagaDictionary.ContainsKey(message.GetType())) { throw new Exception("Handler not found for this message." + serializer.Serialize(message)); } var messageContext = new AFBusMessageContext() { MessageID = Guid.NewGuid(), TransactionID = Guid.NewGuid() }; await InvokeStatelessHandlers(message, messageContext, log).ConfigureAwait(false); await InvokeSagaHandlers(message, messageContext, log).ConfigureAwait(false); }
/// <summary> /// Calls each function referenced by each message in the dictionary. /// </summary> internal async Task HandleAsync <T>(T message, AFBusMessageContext messageContext, ILogger log) where T : class { log?.LogInformation("Message (" + messageContext.MessageID + ") of type " + message.GetType().ToString() + " received in AFBus" + " for transaction " + messageContext.TransactionID); if (!messageHandlersDictionary.ContainsKey(message.GetType()) && !messageToSagaDictionary.ContainsKey(message.GetType())) { throw new Exception("Handler not found for this message." + serializer.Serialize(message)); } //still sometime to wait, go back to queue if (messageContext.MessageDelayedTime != null && messageContext.MessageDelayedTime > TimeSpan.Zero) { var transport = SolveDependency <ISendMessages>(); var differenceUntilFinalWakeUp = messageContext.MessageFinalWakeUpTimeStamp.Value - DateTime.UtcNow; if (differenceUntilFinalWakeUp > TimeSpan.FromSeconds(1)) { if (differenceUntilFinalWakeUp >= transport.MaxDelay()) { messageContext.MessageDelayedTime = transport.MaxDelay(); } else { messageContext.MessageDelayedTime = differenceUntilFinalWakeUp; } await transport.SendMessageAsync(message, messageContext.Destination, messageContext); return; } } await InvokeStatelessHandlers(message, messageContext, log).ConfigureAwait(false); await InvokeSagaHandlers(message, messageContext, log).ConfigureAwait(false); }
public async Task SendMessageAsync <T>(T message, string serviceName, AFBusMessageContext messageContext) where T : class { serviceName = serviceName.ToLower(); CloudQueue queue = queueClient.GetQueueReference(serviceName); if (!createdQueues.Contains(serviceName)) { await queue.CreateIfNotExistsAsync(); createdQueues.Add(serviceName); } var messageAsString = serializer.Serialize(message); var messageWithEnvelope = new AFBusMessageEnvelope() { Context = messageContext, Body = messageAsString }; messageContext.Destination = serviceName; TimeSpan?initialVisibilityDelay = null; if (messageContext.MessageDelayedTime != null && messageContext.MessageDelayedTime >= MaxDelay()) { initialVisibilityDelay = MaxDelay(); messageContext.MessageDelayedTime = MaxDelay(); } else if (messageContext.MessageDelayedTime != null) { initialVisibilityDelay = messageContext.MessageDelayedTime; } if (messageContext.MessageDelayedTime != null && initialVisibilityDelay.Value < TimeSpan.Zero) { initialVisibilityDelay = null; messageContext.MessageDelayedTime = null; } var finalMessage = serializer.Serialize(messageWithEnvelope); //if the message is bigger than the limit put the body in the blob storage if ((finalMessage.Length * sizeof(Char)) > MAX_MESSAGE_SIZE) { var fileName = Guid.NewGuid().ToString("N").ToLower() + ".afbus"; messageWithEnvelope.Context.BodyInFile = true; // Create a container var cloudBlobContainer = cloudBlobClient.GetContainerReference(CONTAINER_NAME.ToLower()); CloudBlockBlob blockBlob = cloudBlobContainer.GetBlockBlobReference(fileName); await blockBlob.UploadTextAsync(messageWithEnvelope.Body); messageWithEnvelope.Body = fileName; finalMessage = serializer.Serialize(messageWithEnvelope); } await queue.AddMessageAsync(new CloudQueueMessage(finalMessage), null, initialVisibilityDelay, null, null).ConfigureAwait(false); }
private async Task <bool> LookForEventsProcessedBySagas <T>(T message, AFBusMessageContext messageContext, ILogger log) where T : class { var instantiated = false; foreach (var sagaInfo in messageToSagaDictionary[message.GetType()]) { var saga = CreateInstance(sagaInfo.SagaType); dynamic sagaDynamic = saga; var sagaMessageToMethod = sagaInfo?.EventsThatCorrelatesSagas?.FirstOrDefault(m => m.Message == message.GetType()); //try to load saga from repository if (sagaMessageToMethod != null) { var locker = new SagaAzureStorageLocker(); object[] lookForInstanceParametersArray = new object[] { message }; sagaDynamic.SagaPersistence = new SagaAzureStoragePersistence(locker, this.lockSaga); var sagasData = await((Task <List <SagaData> >)sagaMessageToMethod.CorrelatingMethod.Invoke(saga, lookForInstanceParametersArray)).ConfigureAwait(false); if (sagasData != null) { //process each saga data independently foreach (var sagaData in sagasData) { try { dynamic finalSagaData = sagaData; SagaData lockedSagaData = await sagaDynamic.SagaPersistence.GetSagaDataAsync <SagaData>(sagaData.PartitionKey, sagaData.RowKey).ConfigureAwait(false); finalSagaData.Timestamp = lockedSagaData.Timestamp; finalSagaData.ETag = lockedSagaData.ETag; finalSagaData.LockID = lockedSagaData.LockID; sagaDynamic.Data = finalSagaData; var bus = new Bus(serializer, SolveDependency <ISendMessages>(), SolveDependency <IPublishEvents>()) { Context = messageContext }; object[] parametersArray = new object[] { bus, message, log }; SagaData typedSagaData = (SagaData)sagaData; log?.LogInformation("Invoke event saga handler " + sagaMessageToMethod.HandlingMethod.ToString() + " for transaction " + messageContext.TransactionID); await((Task)sagaMessageToMethod.HandlingMethod.Invoke(saga, parametersArray)).ConfigureAwait(false); await sagaPersistence.UpdateAsync(sagaDynamic.Data).ConfigureAwait(false); instantiated = true; } catch (Exception ex) { //if there is an error release the lock. log?.LogError(ex.Message, ex); var sagaID = sagaData.PartitionKey + sagaData.RowKey; await locker.ReleaseLock(sagaID, sagaData.LockID); throw; } } } } } return(instantiated); }
private async Task <bool> LookForCommandsProcessedByASaga <T>(T message, AFBusMessageContext messageContext, ILogger log) where T : class { var instantiated = false; foreach (var sagaInfo in messageToSagaDictionary[message.GetType()]) { var saga = CreateInstance(sagaInfo.SagaType);//Activator.CreateInstance(sagaInfo.SagaType); dynamic sagaDynamic = saga; var sagaMessageToMethod = sagaInfo.CommandsThatAreCorrelatedByTheSaga.FirstOrDefault(m => m.Message == message.GetType()); //try to load saga from repository if (sagaMessageToMethod != null) { var locker = new SagaAzureStorageLocker(); object[] lookForInstanceParametersArray = new object[] { message }; sagaDynamic.SagaPersistence = new SagaAzureStoragePersistence(locker, this.lockSaga); dynamic sagaData = await((Task <SagaData>)sagaMessageToMethod.CorrelatingMethod.Invoke(saga, lookForInstanceParametersArray)).ConfigureAwait(false); if (sagaData != null) { try { sagaDynamic.Data = sagaData; var bus = new Bus(serializer, SolveDependency <ISendMessages>(), SolveDependency <IPublishEvents>()) { Context = messageContext }; object[] parametersArray = new object[] { bus, message, log }; SagaData typedSagaData = (SagaData)sagaData; log?.LogInformation("Invoke saga handler " + sagaMessageToMethod.HandlingMethod.ToString() + " for transaction " + messageContext.TransactionID + " with key (" + typedSagaData.PartitionKey.ToString() + "," + typedSagaData.RowKey + ")"); await((Task)sagaMessageToMethod.HandlingMethod.Invoke(saga, parametersArray)).ConfigureAwait(false); await sagaPersistence.UpdateAsync(sagaDynamic.Data).ConfigureAwait(false); instantiated = true; } catch (Exception ex) { //if there is an error release the lock. log?.LogError(ex.Message, ex); var sagaID = sagaData.PartitionKey + sagaData.RowKey; await locker.ReleaseLock(sagaID, sagaData.LockID); throw; } } } sagaMessageToMethod = sagaInfo.CommandsThatActivateTheSaga.FirstOrDefault(m => m.Message == message.GetType()); //if not => create the saga if (!instantiated && sagaMessageToMethod != null) { var bus = new Bus(serializer, SolveDependency <ISendMessages>(), SolveDependency <IPublishEvents>()) { Context = messageContext }; object[] parametersArray = new object[] { bus, message, log }; log?.LogInformation("Invoke saga handler " + sagaMessageToMethod.HandlingMethod.ToString() + " for transaction " + messageContext.TransactionID + " creating new saga"); await((Task)sagaMessageToMethod.HandlingMethod.Invoke(saga, parametersArray)).ConfigureAwait(false); await sagaPersistence.InsertAsync(sagaDynamic.Data).ConfigureAwait(false); SagaData typedSagaData = (SagaData)sagaDynamic.Data; log?.LogInformation("Saga data inserted " + sagaMessageToMethod.HandlingMethod.ToString() + " for transaction " + messageContext.TransactionID + " with key (" + typedSagaData.PartitionKey.ToString() + "," + typedSagaData.RowKey.ToString() + ")"); instantiated = true; } } return(instantiated); }
public async Task PublishEventsAsync <T>(T message, string topicName, AFBusMessageContext messageContext) where T : class { var sender = new MessageSender(SettingsUtil.GetSettings <string>(SETTINGS.AZURE_SERVICEBUS), topicName.ToLower()); CloudStorageAccount storageAccount = CloudStorageAccount.Parse(SettingsUtil.GetSettings <string>(SETTINGS.AZURE_STORAGE)); var messageAsString = serializer.Serialize(message); var messageWithEnvelope = new AFBusMessageEnvelope() { Context = messageContext, Body = messageAsString }; messageContext.Destination = topicName; TimeSpan?initialVisibilityDelay = null; if (messageContext.MessageDelayedTime != null && messageContext.MessageDelayedTime >= MaxDelay()) { initialVisibilityDelay = MaxDelay(); messageContext.MessageDelayedTime = MaxDelay(); } else if (messageContext.MessageDelayedTime != null) { initialVisibilityDelay = messageContext.MessageDelayedTime; } if (messageContext.MessageDelayedTime != null && initialVisibilityDelay.Value < TimeSpan.Zero) { initialVisibilityDelay = null; messageContext.MessageDelayedTime = null; } var finalMessage = serializer.Serialize(messageWithEnvelope); //if the message is bigger than the limit put the body in the blob storage if ((finalMessage.Length * sizeof(Char)) > MAX_MESSAGE_SIZE) { var fileName = Guid.NewGuid().ToString("N").ToLower() + ".afbus"; messageWithEnvelope.Context.BodyInFile = true; CloudBlobClient cloudBlobClient = storageAccount.CreateCloudBlobClient(); // Create a container var cloudBlobContainer = cloudBlobClient.GetContainerReference(CONTAINER_NAME.ToLower()); await cloudBlobContainer.CreateIfNotExistsAsync().ConfigureAwait(false); CloudBlockBlob blockBlob = cloudBlobContainer.GetBlockBlobReference(fileName); await blockBlob.UploadTextAsync(messageWithEnvelope.Body); messageWithEnvelope.Body = fileName; finalMessage = serializer.Serialize(messageWithEnvelope); } var finalSBMessage = new Message(Encoding.UTF8.GetBytes(finalMessage)) { ContentType = "application/json", Label = topicName, MessageId = messageContext.MessageID.ToString(), TimeToLive = TimeSpan.FromDays(10) }; if (messageContext.MessageDelayedTime.HasValue) { finalSBMessage.ScheduledEnqueueTimeUtc = DateTime.UtcNow + messageContext.MessageDelayedTime.Value; } await sender.SendAsync(finalSBMessage).ConfigureAwait(false); }