public string GetDestinationQueueUrlByName(string address, ITransactionContext transactionContext) { var url = m_concurrentDictionarySqsUris.GetOrAdd(address.ToLowerInvariant(), key => { if (Uri.IsWellFormedUriString(address, UriKind.Absolute)) { return(address); } var client = m_AmazonInternalSettings.CreateSqsClient(transactionContext); var task = client.GetQueueUrlAsync(address); AsyncHelpers.RunSync(() => task); var urlResponse = task.Result; if (urlResponse.HttpStatusCode == HttpStatusCode.OK) { return(urlResponse.QueueUrl); } throw new RebusApplicationException($"could not find Url for address: {address} - got errorcode: {urlResponse.HttpStatusCode}"); }); return(url); }
private async Task SendOutgoingMessages(ConcurrentQueue <AmazonOutgoingMessage> outgoingMessages, ITransactionContext context) { if (!outgoingMessages.Any()) { return; } var client = _amazonInternalSettings.CreateSqsClient(context); var messagesByDestination = outgoingMessages.GroupBy(m => m.DestinationAddress).ToList(); await Task.WhenAll(messagesByDestination.Select(async batch => { var entries = batch.Select(message => { var transportMessage = message.TransportMessage; var headers = transportMessage.Headers; var messageId = headers[Headers.MessageId]; var sqsMessage = new AmazonTransportMessage(transportMessage.Headers, StringHelper.GetBody(transportMessage.Body)); var entry = new SendMessageBatchRequestEntry(messageId, _amazonInternalSettings.MessageSerializer.Serialize(sqsMessage)); var delaySeconds = GetDelaySeconds(headers); if (delaySeconds != null) { entry.DelaySeconds = delaySeconds.Value; } return(entry); }).ToList(); var destinationUrl = _amazonSqsQueueContext.GetDestinationQueueUrlByName(batch.Key, context); foreach (var batchToSend in entries.Batch(10)) { var request = new SendMessageBatchRequest(destinationUrl, batchToSend); var response = await client.SendMessageBatchAsync(request); if (response.Failed.Count == 0) { continue; } var failed = response.Failed.Select(f => new AmazonSQSException($"Failed {f.Message} with Id={f.Id}, Code={f.Code}, SenderFault={f.SenderFault}")); throw new AggregateException(failed); } })); }
public static async Task CheckSqsPolicy(this IAmazonInternalSettings amazonInternalSettings, ITransactionContext transactionContext, string destinationQueueUrlByName, SqsInfo sqsInformation, string topicArn) { var logger = amazonInternalSettings.RebusLoggerFactory.GetLogger(); var sqsClient = amazonInternalSettings.CreateSqsClient(transactionContext); var attributes = await sqsClient.GetAttributesAsync(destinationQueueUrlByName); var policyKey = "Policy"; var statement = new Statement(Statement.StatementEffect.Allow).WithPrincipals(Principal.AllUsers).WithResources(new Resource(sqsInformation.Arn)).WithConditions(ConditionFactory.NewSourceArnCondition(topicArn)).WithActionIdentifiers(SQSActionIdentifiers.SendMessage); Policy sqsPolicy; var setPolicy = false; if (attributes.ContainsKey(policyKey)) { logger.Debug($"Updating existing policy on sqs queue {0} for topic {1}", sqsInformation.Url, topicArn); var policyString = attributes[policyKey]; attributes = new Dictionary <string, string>(); sqsPolicy = Policy.FromJson(policyString); if (sqsPolicy.CheckIfStatementExists(statement) == false) { sqsPolicy = sqsPolicy.WithStatements(statement); attributes.Add(policyKey, sqsPolicy.ToJson()); setPolicy = true; } } else { logger.Debug($"Creating policy on sqs queue {0} for topic {1}", sqsInformation.Url, topicArn); attributes = new Dictionary <string, string>(); sqsPolicy = new Policy().WithStatements(statement); attributes.Add(policyKey, sqsPolicy.ToJson()); setPolicy = true; } if (setPolicy) { await sqsClient.SetAttributesAsync(sqsInformation.Url, attributes); } }
/// <inheritdoc /> public async Task <TransportMessage> Receive(ITransactionContext context, string address, CancellationToken cancellationToken) { if (context == null) { throw new ArgumentNullException(nameof(context)); } if (address == null) { throw new InvalidOperationException("This Amazon SQS transport does not have an input queue, hence it is not possible to receive anything"); } var queueUrl = m_amazonSqsQueueContext.GetDestinationQueueUrlByName(address, context); if (string.IsNullOrWhiteSpace(queueUrl)) { throw new InvalidOperationException("The queue URL is empty - has the transport not been initialized?"); } var client = m_amazonInternalSettings.CreateSqsClient(context); var request = new ReceiveMessageRequest(queueUrl) { MaxNumberOfMessages = 1, WaitTimeSeconds = m_amazonInternalSettings.AmazonSnsAndSqsTransportOptions.ReceiveWaitTimeSeconds, AttributeNames = new List <string>(new[] { "All" }), MessageAttributeNames = new List <string>(new[] { "All" }) }; var response = await client.ReceiveMessageAsync(request, cancellationToken); if (response.Messages.Any() == false) { return(null); } var sqsMessage = response.Messages.First(); var renewalTask = CreateRenewalTaskForMessage(sqsMessage, queueUrl, client); context.OnCompleted(async() => { renewalTask.Dispose(); // if we get this far, we don't want to pass on the cancellation token // ReSharper disable once MethodSupportsCancellation await client.DeleteMessageAsync(new DeleteMessageRequest(queueUrl, sqsMessage.ReceiptHandle)); }); context.OnAborted(() => { renewalTask.Dispose(); Task.Run(() => client.ChangeMessageVisibilityAsync(queueUrl, sqsMessage.ReceiptHandle, 0, cancellationToken), cancellationToken).Wait(cancellationToken); }); IAmazonMessageProcessor amazonMessageProcessor = _amazonMessageProcessorFactory.Create(sqsMessage); var transportMessage = amazonMessageProcessor.ProcessMessage(); if (transportMessage.MessageIsExpired(sqsMessage)) { // if the message is expired , we don't want to pass on the cancellation token // ReSharper disable once MethodSupportsCancellation await client.DeleteMessageAsync(new DeleteMessageRequest(queueUrl, sqsMessage.ReceiptHandle)); return(null); } renewalTask.Start(); return(transportMessage); }