From e9896fa9ea9e410ecb0bcb356b8940149ebf073d Mon Sep 17 00:00:00 2001 From: Daniel Marbach Date: Thu, 29 May 2025 14:51:30 +0200 Subject: [PATCH 1/2] Update to SQS 7.4.0 and v4 SDK --- src/Directory.Packages.props | 8 ++++---- .../AmazonSQSQuery.cs | 16 ++++++++++------ .../QueueAttributesRequestCache.cs | 18 +++++++----------- 3 files changed, 21 insertions(+), 21 deletions(-) diff --git a/src/Directory.Packages.props b/src/Directory.Packages.props index 6b6ac9a91d..c725b2191e 100644 --- a/src/Directory.Packages.props +++ b/src/Directory.Packages.props @@ -5,8 +5,8 @@ - - + + @@ -31,7 +31,7 @@ - + @@ -91,4 +91,4 @@ - \ No newline at end of file + diff --git a/src/ServiceControl.Transports.SQS/AmazonSQSQuery.cs b/src/ServiceControl.Transports.SQS/AmazonSQSQuery.cs index df6b946077..7fab64cc45 100644 --- a/src/ServiceControl.Transports.SQS/AmazonSQSQuery.cs +++ b/src/ServiceControl.Transports.SQS/AmazonSQSQuery.cs @@ -14,6 +14,7 @@ namespace ServiceControl.Transports.SQS; using Amazon.CloudWatch.Model; using Amazon.Runtime; using Amazon.Runtime.CredentialManagement; +using Amazon.Runtime.Credentials; using Amazon.SQS; using Amazon.SQS.Model; using BrokerThroughput; @@ -29,7 +30,7 @@ public class AmazonSQSQuery(ILogger logger, TimeProvider timePro protected override void InitializeCore(ReadOnlyDictionary settings) { var sqsConnectionString = new SQSTransportConnectionString(transportSettings.ConnectionString); - AWSCredentials credentials = FallbackCredentialsFactory.GetCredentials(); + AWSCredentials credentials = DefaultAWSCredentialsIdentityResolver.GetCredentials(); RegionEndpoint? regionEndpoint = null; if (settings.TryGetValue(AmazonSQSSettings.Profile, out string? profile)) { @@ -197,8 +198,8 @@ public override async IAsyncEnumerable GetThroughputPerDay(IBro { Namespace = "AWS/SQS", MetricName = "NumberOfMessagesDeleted", - StartTimeUtc = startDate.ToDateTime(TimeOnly.MinValue), - EndTimeUtc = endDate.ToDateTime(TimeOnly.MaxValue), + StartTime = startDate.ToDateTime(TimeOnly.MinValue), + EndTime = endDate.ToDateTime(TimeOnly.MaxValue), Period = 24 * 60 * 60, // 1 day Statistics = ["Sum"], Dimensions = [ @@ -217,12 +218,15 @@ public override async IAsyncEnumerable GetThroughputPerDay(IBro currentDate = currentDate.AddDays(1); } - foreach (var datapoint in resp.Datapoints) + foreach (var datapoint in resp.Datapoints ?? []) { // There is a bug in the AWS SDK. The timestamp is actually UTC time, eventhough the DateTime returned type says Local // See https://github.com/aws/aws-sdk-net/issues/167 // So do not convert the timestamp to UTC time! - data[DateOnly.FromDateTime(datapoint.Timestamp)].TotalThroughput = (long)datapoint.Sum; + if (datapoint.Timestamp.HasValue) + { + data[DateOnly.FromDateTime(datapoint.Timestamp.Value)].TotalThroughput = (long)datapoint.Sum.GetValueOrDefault(0); + } } foreach (QueueThroughput queueThroughput in data.Values) @@ -244,7 +248,7 @@ public override async IAsyncEnumerable GetQueueNames( { var response = await sqs!.ListQueuesAsync(request, cancellationToken); - foreach (var queue in response.QueueUrls.Select(url => url.Split('/')[4])) + foreach (var queue in (response.QueueUrls ?? []).Select(url => url.Split('/')[4])) { if (!queue.EndsWith("-delay.fifo", StringComparison.OrdinalIgnoreCase)) { diff --git a/src/ServiceControl.Transports.SQS/QueueAttributesRequestCache.cs b/src/ServiceControl.Transports.SQS/QueueAttributesRequestCache.cs index 74eb64d82a..df6c22f447 100644 --- a/src/ServiceControl.Transports.SQS/QueueAttributesRequestCache.cs +++ b/src/ServiceControl.Transports.SQS/QueueAttributesRequestCache.cs @@ -6,14 +6,8 @@ using Amazon.SQS; using Amazon.SQS.Model; - class QueueAttributesRequestCache + class QueueAttributesRequestCache(IAmazonSQS sqsClient) { - public QueueAttributesRequestCache(IAmazonSQS sqsClient) - { - cache = new ConcurrentDictionary(); - this.sqsClient = sqsClient; - } - public async Task GetQueueAttributesRequest(string queueName, CancellationToken cancellationToken = default) { if (cache.TryGetValue(queueName, out var attReq)) @@ -23,8 +17,11 @@ public async Task GetQueueAttributesRequest(string qu var queueUrl = await GetQueueUrl(queueName, cancellationToken); - attReq = new GetQueueAttributesRequest { QueueUrl = queueUrl }; - attReq.AttributeNames.Add("ApproximateNumberOfMessages"); + attReq = new GetQueueAttributesRequest + { + QueueUrl = queueUrl, + AttributeNames = ["ApproximateNumberOfMessages"] + }; cache[queueName] = attReq; @@ -37,7 +34,6 @@ async Task GetQueueUrl(string queueName, CancellationToken cancellationT return response.QueueUrl; } - ConcurrentDictionary cache; - IAmazonSQS sqsClient; + readonly ConcurrentDictionary cache = new(); } } \ No newline at end of file From c5c6ae11346e76cd79faac3a2fdbfd93f32a69a6 Mon Sep 17 00:00:00 2001 From: John Simons Date: Fri, 30 May 2025 09:10:24 +1000 Subject: [PATCH 2/2] Validate region name is within allowed names This is required because RegionEndpoint.GetBySystemName() returns `unknown` instead of throwing. --- src/ServiceControl.Transports.SQS/AmazonSQSQuery.cs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/ServiceControl.Transports.SQS/AmazonSQSQuery.cs b/src/ServiceControl.Transports.SQS/AmazonSQSQuery.cs index 7fab64cc45..0c54ca7f0b 100644 --- a/src/ServiceControl.Transports.SQS/AmazonSQSQuery.cs +++ b/src/ServiceControl.Transports.SQS/AmazonSQSQuery.cs @@ -92,9 +92,15 @@ protected override void InitializeCore(ReadOnlyDictionary settin } } + bool IsValidAwsRegion(string region) => RegionEndpoint.EnumerableAllRegions.Any(r => r.SystemName.Equals(region, StringComparison.OrdinalIgnoreCase)); + if (settings.TryGetValue(AmazonSQSSettings.Region, out string? region)) { string? previousSetSystemName = regionEndpoint?.SystemName; + if (!IsValidAwsRegion(region)) + { + throw new ArgumentException("Invalid region endpoint provided"); + } regionEndpoint = RegionEndpoint.GetBySystemName(region); Diagnostics.Append($"Region set to \"{regionEndpoint.SystemName}\""); @@ -109,6 +115,10 @@ protected override void InitializeCore(ReadOnlyDictionary settin { if (sqsConnectionString.Region != null) { + if (!IsValidAwsRegion(sqsConnectionString.Region)) + { + throw new ArgumentException("Invalid region endpoint provided"); + } regionEndpoint = RegionEndpoint.GetBySystemName(sqsConnectionString.Region); Diagnostics.AppendLine( $"Region not set, defaulted to using \"{regionEndpoint.SystemName}\" from the ConnectionString used by instance");