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);
            }
        }
Ejemplo n.º 4
0
        /// <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);
        }