-
Notifications
You must be signed in to change notification settings - Fork 259
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Improve support to AWS SQS/SNS #3437
base: master
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
❌ Code Health Quality Gates: FAILED
Change in average Code Health of affected files: -0.12 (9.65 -> 9.53)
- Declining Code Health: 4 findings(s) 🚩
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
❌ Code Health Quality Gates: FAILED
Change in average Code Health of affected files: -0.10 (9.46 -> 9.36)
- Declining Code Health: 8 findings(s) 🚩
Hi @lillo42 - thanks for this. To lift out of inline above, the usual strategy would be: Folders for each queue type:
Put the existing tests in Standard and duplicate the tests in Fifo, but with the changed semantics. I tend to prefer being explicit in tests, over worrying about duplication there. |
PS @lillo42 if you have time. One weakness in Brighter is that you have to produce to SNS and can't target a queue. It would be good to allow the queue to be the target. We now do something similar for ASB. Probably pop that in a separate PR though? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
❌ Code Health Quality Gates: FAILED
Change in average Code Health of affected files: +0.05 (9.61 -> 9.66)
- Declining Code Health: 6 findings(s) 🚩
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks great. You may also need to support async approaches, you'll note the increased footprint when you merge in master. It is a little crude, as we just tend to duplicate in tests, but I sort of prefer tests to be explicit
tests/Paramore.Brighter.AWS.Tests/MessagingGateway/When_infastructure_exists_can_assume.cs
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
❌ Code Health Quality Gates: FAILED
Change in average Code Health of affected files: +0.10 (9.50 -> 9.60)
- Declining Code Health: 5 findings(s) 🚩
Sure no problem, I can add it to this PR. |
Thanks @lillo42. Apologies in advance for the merge issues caused by the Reactor(Blocking)/Proactor(Non-Blocking) enhancement |
… localstack and rename SQS to SNS
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
❌ Code Health Quality Gates: FAILED
Change in average Code Health of affected files: +0.05 (9.60 -> 9.65)
- Declining Code Health: 5 findings(s) 🚩
We still have a credentials issue on the AWS tests, that means they don't show up here. I need to fix that too. Let me see if I can fix that and merge to main, so that we can at least see what is passing |
RoutingKey topic, | ||
TopicFindBy topicFindBy, | ||
SnsAttributes? attributes, | ||
OnMissingChannel makeTopic = OnMissingChannel.Create, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we make makeTopic the last parameter? That keeps it in sync with other producers
src/Paramore.Brighter.MessagingGateway.AWSSQS/SnsMessageProducer.cs
Outdated
Show resolved
Hide resolved
src/Paramore.Brighter.MessagingGateway.AWSSQS/SqsMessageConsumer.cs
Outdated
Show resolved
Hide resolved
namespace System.Diagnostics.CodeAnalysis; | ||
|
||
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)] | ||
public sealed class MemberNotNullWhenAttribute : Attribute |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Out of interest, we have an open conversation on using polyfills vs dropping netstandard20
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I tend to prefer drop support for netstandard20
, but depending on how many downloads we have today on .NET standard maybe we still have people using Brighter with .NET Framework 4
Maybe on V11 we can remove the support for .NET Standard completed, and put a warning on V10 saying that is the last version of supporting .NET Standard/Framework
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, you may be right that it would be 0-warning if we dropped it with V10 and we should declare that will happen with V11.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
❌ Code Health Quality Gates: FAILED
Change in average Code Health of affected files: +0.13 (9.61 -> 9.74)
- Declining Code Health: 9 findings(s) 🚩
- Improving Code Health: 1 findings(s) ✅
public Message CreateMessage(Amazon.SQS.Model.Message sqsMessage) | ||
{ | ||
var topic = HeaderResult<RoutingKey>.Empty(); | ||
var messageId = HeaderResult<string?>.Empty(); | ||
|
||
Message message; | ||
try |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
❌ Getting worse: Complex Method
CreateMessage increases in cyclomatic complexity from 10 to 12, threshold = 9
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
❌ Code Health Quality Gates: FAILED
Change in average Code Health of affected files: +0.43 (9.42 -> 9.85)
- Declining Code Health: 10 findings(s) 🚩
- Improving Code Health: 5 findings(s) ✅
|
||
public Message CreateMessage(Amazon.SQS.Model.Message sqsMessage) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
❌ Getting worse: Complex Method
CreateMessage increases in cyclomatic complexity from 10 to 13, threshold = 9
RoutingKey topic, | ||
TopicFindBy topicFindBy, | ||
SnsAttributes? attributes, | ||
OnMissingChannel makeTopic = OnMissingChannel.Create, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
❌ New issue: Code Duplication
The module contains 2 functions with similar structure: EnsureQueueAsync,EnsureTopicAsync
private async Task<string> CreateQueueAsync( | ||
string queueName, | ||
SqsAttributes? sqsAttributes, | ||
OnMissingChannel makeChannel, | ||
CancellationToken cancellationToken) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
❌ New issue: Complex Method
CreateQueueAsync has a cyclomatic complexity of 17, threshold = 9
private async Task<string> CreateDeadLetterQueueAsync( | ||
SqsAttributes sqsAttributes, | ||
CancellationToken cancellationToken) | ||
{ | ||
using var sqsClient = _awsClientFactory.CreateSqsClient(); | ||
|
||
var queueName = sqsAttributes.RedrivePolicy!.DeadlLetterQueueName; | ||
|
||
var tags = new Dictionary<string, string> { { "Source", "Brighter" } }; | ||
var attributes = new Dictionary<string, string?>(); | ||
if (sqsAttributes.Type == SnsSqsType.Fifo) | ||
{ | ||
queueName = queueName.ToValidSQSQueueName(true); | ||
|
||
attributes.Add(QueueAttributeName.FifoQueue, "true"); | ||
if (sqsAttributes.ContentBasedDeduplication) | ||
{ | ||
attributes.Add(QueueAttributeName.ContentBasedDeduplication, "true"); | ||
} | ||
|
||
if (sqsAttributes is { DeduplicationScope: not null, FifoThroughputLimit: not null }) | ||
{ | ||
attributes.Add(QueueAttributeName.FifoThroughputLimit, | ||
sqsAttributes.FifoThroughputLimit.Value.ToString()); | ||
attributes.Add(QueueAttributeName.DeduplicationScope, sqsAttributes.DeduplicationScope switch | ||
{ | ||
DeduplicationScope.MessageGroup => "messageGroup", | ||
_ => "queue" | ||
}); | ||
} | ||
} | ||
|
||
string queueUrl; | ||
|
||
try | ||
{ | ||
var request = new CreateQueueRequest(queueName) { Attributes = attributes, Tags = tags }; | ||
// create queue is idempotent, so safe to call even if queue already exists | ||
var response = await sqsClient.CreateQueueAsync(request, cancellationToken); | ||
|
||
queueUrl = response.QueueUrl ?? throw new InvalidOperationException( | ||
$"Could not find create DLQ, status: {response.HttpStatusCode}"); | ||
} | ||
catch (QueueNameExistsException) | ||
{ | ||
var response = await sqsClient.GetQueueUrlAsync(queueName, cancellationToken); | ||
queueUrl = response.QueueUrl; | ||
} | ||
|
||
var attributesResponse = await sqsClient.GetQueueAttributesAsync( | ||
new GetQueueAttributesRequest { QueueUrl = queueUrl, AttributeNames = [QueueAttributeName.QueueArn] }, | ||
cancellationToken); | ||
|
||
if (attributesResponse.HttpStatusCode != HttpStatusCode.OK) | ||
{ | ||
throw new InvalidOperationException( | ||
$"Could not find ARN of DLQ, status: {attributesResponse.HttpStatusCode}"); | ||
} | ||
|
||
return attributesResponse.QueueARN; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
❌ New issue: Complex Method
CreateDeadLetterQueueAsync has a cyclomatic complexity of 10, threshold = 9
private async Task<string> CreateQueueAsync( | ||
string queueName, | ||
SqsAttributes? sqsAttributes, | ||
OnMissingChannel makeChannel, | ||
CancellationToken cancellationToken) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
❌ New issue: Bumpy Road Ahead
CreateQueueAsync has 3 blocks with nested conditional logic. Any nesting of 2 or deeper is considered. Threshold is one single, nested block per function
private async Task SubscribeToTopicAsync( | ||
string topicArn, | ||
string queueUrl, | ||
SqsAttributes? sqsAttributes, | ||
AmazonSQSClient sqsClient, | ||
AmazonSimpleNotificationServiceClient snsClient) | ||
{ | ||
var arn = await snsClient.SubscribeQueueAsync(topicArn, sqsClient, queueUrl); | ||
if (string.IsNullOrEmpty(arn)) | ||
{ | ||
throw new InvalidOperationException( | ||
$"Could not subscribe to topic: {topicArn} from queue: {queueUrl} in region {AwsConnection.Region}"); | ||
} | ||
|
||
var response = await snsClient.SetSubscriptionAttributesAsync( | ||
new SetSubscriptionAttributesRequest(arn, | ||
"RawMessageDelivery", | ||
sqsAttributes?.RawMessageDelivery.ToString()) | ||
); | ||
|
||
if (response.HttpStatusCode != HttpStatusCode.OK) | ||
{ | ||
throw new InvalidOperationException("Unable to set subscription attribute for raw message delivery"); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ℹ New issue: Excess Number of Function Arguments
SubscribeToTopicAsync has 5 arguments, threshold = 4
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is a lot here, and it is a great addition. A couple of minor tweaks, which are more o do with style over anything else.
src/Paramore.Brighter.MessagingGateway.AWSSQS/SnsMessageProducer.cs
Outdated
Show resolved
Hide resolved
|
||
var arnElements = s!.Split(':'); | ||
var topic = arnElements[(int)ARNAmazonSNS.TopicName]; | ||
var topic = topicArn.GetValueInString() ?? string.Empty; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The earlier version reduces nesting by returning early, which is generally preferable
} | ||
} | ||
|
||
var messageAttributes = new Dictionary<string, MessageAttributeValue> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Typically we factor this into a publisher, to keep the producer clean of all the header manipulation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
❌ Code Health Quality Gates: FAILED
Change in average Code Health of affected files: +0.38 (9.48 -> 9.86)
- Declining Code Health: 8 findings(s) 🚩
- Improving Code Health: 5 findings(s) ✅
src/Paramore.Brighter.MessagingGateway.AWSSQS/RoutingKeyType.cs
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
❌ Code Health Quality Gates: FAILED
Change in average Code Health of affected files: +0.38 (9.48 -> 9.86)
- Declining Code Health: 8 findings(s) 🚩
- Improving Code Health: 5 findings(s) ✅
public SqsSubscription( | ||
SubscriptionName? name = null, | ||
ChannelName? channelName = null, | ||
RoutingKey? routingKey = null, | ||
int bufferSize = 1, | ||
int noOfPerformers = 1, | ||
TimeSpan? timeOut = null, | ||
int requeueCount = -1, | ||
TimeSpan? requeueDelay = null, | ||
int unacceptableMessageLimit = 0, | ||
MessagePumpType messagePumpType = MessagePumpType.Proactor, | ||
IAmAChannelFactory? channelFactory = null, | ||
int lockTimeout = 10, | ||
int delaySeconds = 0, | ||
int messageRetentionPeriod = 345600, | ||
TopicFindBy findTopicBy = TopicFindBy.Name, | ||
string? iAmPolicy = null, | ||
RedrivePolicy? redrivePolicy = null, | ||
SnsAttributes? snsAttributes = null, | ||
Dictionary<string, string>? tags = null, | ||
OnMissingChannel makeChannels = OnMissingChannel.Create, | ||
bool rawMessageDelivery = true, | ||
TimeSpan? emptyChannelDelay = null, | ||
TimeSpan? channelFailureDelay = null, | ||
SnsSqsType sqsType = SnsSqsType.Standard, | ||
bool contentBasedDeduplication = true, | ||
DeduplicationScope? deduplicationScope = null, | ||
int? fifoThroughputLimit = null, | ||
ChannelType channelType = ChannelType.PubSub, | ||
QueueFindBy findQueueBy = QueueFindBy.Name | ||
) | ||
: base(typeof(T), name, channelName, routingKey, bufferSize, noOfPerformers, timeOut, requeueCount, | ||
requeueDelay, | ||
unacceptableMessageLimit, messagePumpType, channelFactory, lockTimeout, delaySeconds, | ||
messageRetentionPeriod, findTopicBy, | ||
iAmPolicy, redrivePolicy, snsAttributes, tags, makeChannels, rawMessageDelivery, emptyChannelDelay, | ||
channelFailureDelay, sqsType, contentBasedDeduplication, deduplicationScope, fifoThroughputLimit, | ||
channelType, findQueueBy) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ℹ Getting worse: Constructor Over-Injection
SqsSubscription increases from 23 to 29 arguments, threshold = 5
if (delay != null) | ||
{ | ||
request.DelaySeconds = (int)delay.Value.TotalSeconds; | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@iancooper question about DelaySeconds
AWS SQS supports max of 15min, should I add an extra logic to support longer delay? Or let it throw?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just to confirm our conversation, reduce to max, and log that it was reduced.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
❌ Code Health Quality Gates: FAILED
Change in average Code Health of affected files: +0.38 (9.48 -> 9.86)
- Declining Code Health: 10 findings(s) 🚩
- Improving Code Health: 5 findings(s) ✅
public SqsSubscription( | ||
Type dataType, | ||
SubscriptionName? name = null, | ||
ChannelName? channelName = null, | ||
RoutingKey? routingKey = null, | ||
int bufferSize = 1, | ||
int noOfPerformers = 1, | ||
TimeSpan? timeOut = null, | ||
int requeueCount = -1, | ||
TimeSpan? requeueDelay = null, | ||
int unacceptableMessageLimit = 0, | ||
MessagePumpType messagePumpType = MessagePumpType.Unknown, | ||
IAmAChannelFactory? channelFactory = null, | ||
int lockTimeout = 10, | ||
int delaySeconds = 0, | ||
int messageRetentionPeriod = 345600, | ||
TopicFindBy findTopicBy = TopicFindBy.Name, | ||
string? iAmPolicy = null, | ||
RedrivePolicy? redrivePolicy = null, | ||
SnsAttributes? snsAttributes = null, | ||
Dictionary<string, string>? tags = null, | ||
OnMissingChannel makeChannels = OnMissingChannel.Create, | ||
bool rawMessageDelivery = true, | ||
TimeSpan? emptyChannelDelay = null, | ||
TimeSpan? channelFailureDelay = null, | ||
SnsSqsType sqsType = SnsSqsType.Standard, | ||
bool contentBasedDeduplication = true, | ||
DeduplicationScope? deduplicationScope = null, | ||
int? fifoThroughputLimit = null, | ||
ChannelType channelType = ChannelType.PubSub, | ||
QueueFindBy findQueueBy = QueueFindBy.Name | ||
) | ||
: base(dataType, name, channelName, routingKey, bufferSize, noOfPerformers, timeOut, requeueCount, | ||
requeueDelay, unacceptableMessageLimit, messagePumpType, channelFactory, makeChannels, emptyChannelDelay, | ||
channelFailureDelay) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ℹ Getting worse: Constructor Over-Injection
SqsSubscription increases from 24 to 30 arguments, threshold = 5
public async Task<string?> SendAsync(Message message, TimeSpan? delay, CancellationToken cancellationToken) | ||
{ | ||
var request = new SendMessageRequest | ||
{ | ||
QueueUrl = _queueUrl, | ||
MessageBody = message.Body.Value | ||
}; | ||
|
||
delay ??= TimeSpan.Zero; | ||
if (delay > TimeSpan.Zero) | ||
{ | ||
// SQS has a hard limit of 15min for Delay in Seconds | ||
if (delay.Value > s_maxDelay) | ||
{ | ||
delay = s_maxDelay; | ||
s_logger.LogWarning("Set delay from {CurrentDelay} to 15min (SQS support up to 15min)", delay); | ||
} | ||
|
||
request.DelaySeconds = (int)delay.Value.TotalSeconds; | ||
} | ||
|
||
if (_queueType == SnsSqsType.Fifo) | ||
{ | ||
request.MessageGroupId = message.Header.PartitionKey; | ||
if (message.Header.Bag.TryGetValue(HeaderNames.DeduplicationId, out var deduplicationId)) | ||
{ | ||
request.MessageDeduplicationId = (string)deduplicationId; | ||
} | ||
} | ||
|
||
var messageAttributes = new Dictionary<string, MessageAttributeValue> | ||
{ | ||
[HeaderNames.Id] = | ||
new() { StringValue = message.Header.MessageId, DataType = "String" }, | ||
[HeaderNames.Topic] = new() { StringValue = _queueUrl, DataType = "String" }, | ||
[HeaderNames.ContentType] = new() { StringValue = message.Header.ContentType, DataType = "String" }, | ||
[HeaderNames.CorrelationId] = | ||
new() { StringValue = message.Header.CorrelationId, DataType = "String" }, | ||
[HeaderNames.HandledCount] = | ||
new() { StringValue = Convert.ToString(message.Header.HandledCount), DataType = "String" }, | ||
[HeaderNames.MessageType] = | ||
new() { StringValue = message.Header.MessageType.ToString(), DataType = "String" }, | ||
[HeaderNames.Timestamp] = new() | ||
{ | ||
StringValue = Convert.ToString(message.Header.TimeStamp), DataType = "String" | ||
} | ||
}; | ||
|
||
if (!string.IsNullOrEmpty(message.Header.ReplyTo)) | ||
{ | ||
messageAttributes.Add(HeaderNames.ReplyTo, | ||
new MessageAttributeValue { StringValue = message.Header.ReplyTo, DataType = "String" }); | ||
} | ||
|
||
if (!string.IsNullOrEmpty(message.Header.Subject)) | ||
{ | ||
messageAttributes.Add(HeaderNames.Subject, | ||
new MessageAttributeValue { StringValue = message.Header.Subject, DataType = "String" }); | ||
} | ||
|
||
// we can set up to 10 attributes; we have set 6 above, so use a single JSON object as the bag | ||
var bagJson = JsonSerializer.Serialize(message.Header.Bag, JsonSerialisationOptions.Options); | ||
messageAttributes[HeaderNames.Bag] = new() { StringValue = bagJson, DataType = "String" }; | ||
request.MessageAttributes = messageAttributes; | ||
|
||
var response = await _client.SendMessageAsync(request, cancellationToken); | ||
if (response.HttpStatusCode is HttpStatusCode.OK or HttpStatusCode.Created | ||
or HttpStatusCode.Accepted) | ||
{ | ||
return response.MessageId; | ||
} | ||
|
||
return null; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
❌ New issue: Complex Method
SendAsync has a cyclomatic complexity of 9, threshold = 9
public async Task<string?> SendAsync(Message message, TimeSpan? delay, CancellationToken cancellationToken) | ||
{ | ||
var request = new SendMessageRequest | ||
{ | ||
QueueUrl = _queueUrl, | ||
MessageBody = message.Body.Value | ||
}; | ||
|
||
delay ??= TimeSpan.Zero; | ||
if (delay > TimeSpan.Zero) | ||
{ | ||
// SQS has a hard limit of 15min for Delay in Seconds | ||
if (delay.Value > s_maxDelay) | ||
{ | ||
delay = s_maxDelay; | ||
s_logger.LogWarning("Set delay from {CurrentDelay} to 15min (SQS support up to 15min)", delay); | ||
} | ||
|
||
request.DelaySeconds = (int)delay.Value.TotalSeconds; | ||
} | ||
|
||
if (_queueType == SnsSqsType.Fifo) | ||
{ | ||
request.MessageGroupId = message.Header.PartitionKey; | ||
if (message.Header.Bag.TryGetValue(HeaderNames.DeduplicationId, out var deduplicationId)) | ||
{ | ||
request.MessageDeduplicationId = (string)deduplicationId; | ||
} | ||
} | ||
|
||
var messageAttributes = new Dictionary<string, MessageAttributeValue> | ||
{ | ||
[HeaderNames.Id] = | ||
new() { StringValue = message.Header.MessageId, DataType = "String" }, | ||
[HeaderNames.Topic] = new() { StringValue = _queueUrl, DataType = "String" }, | ||
[HeaderNames.ContentType] = new() { StringValue = message.Header.ContentType, DataType = "String" }, | ||
[HeaderNames.CorrelationId] = | ||
new() { StringValue = message.Header.CorrelationId, DataType = "String" }, | ||
[HeaderNames.HandledCount] = | ||
new() { StringValue = Convert.ToString(message.Header.HandledCount), DataType = "String" }, | ||
[HeaderNames.MessageType] = | ||
new() { StringValue = message.Header.MessageType.ToString(), DataType = "String" }, | ||
[HeaderNames.Timestamp] = new() | ||
{ | ||
StringValue = Convert.ToString(message.Header.TimeStamp), DataType = "String" | ||
} | ||
}; | ||
|
||
if (!string.IsNullOrEmpty(message.Header.ReplyTo)) | ||
{ | ||
messageAttributes.Add(HeaderNames.ReplyTo, | ||
new MessageAttributeValue { StringValue = message.Header.ReplyTo, DataType = "String" }); | ||
} | ||
|
||
if (!string.IsNullOrEmpty(message.Header.Subject)) | ||
{ | ||
messageAttributes.Add(HeaderNames.Subject, | ||
new MessageAttributeValue { StringValue = message.Header.Subject, DataType = "String" }); | ||
} | ||
|
||
// we can set up to 10 attributes; we have set 6 above, so use a single JSON object as the bag | ||
var bagJson = JsonSerializer.Serialize(message.Header.Bag, JsonSerialisationOptions.Options); | ||
messageAttributes[HeaderNames.Bag] = new() { StringValue = bagJson, DataType = "String" }; | ||
request.MessageAttributes = messageAttributes; | ||
|
||
var response = await _client.SendMessageAsync(request, cancellationToken); | ||
if (response.HttpStatusCode is HttpStatusCode.OK or HttpStatusCode.Created | ||
or HttpStatusCode.Accepted) | ||
{ | ||
return response.MessageId; | ||
} | ||
|
||
return null; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
❌ New issue: Bumpy Road Ahead
SendAsync has 2 blocks with nested conditional logic. Any nesting of 2 or deeper is considered. Threshold is one single, nested block per function
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
❌ Code Health Quality Gates: FAILED
Change in average Code Health of affected files: +0.38 (9.48 -> 9.86)
- Declining Code Health: 10 findings(s) 🚩
- Improving Code Health: 5 findings(s) ✅
Hohohoho 🎅
How should I handle the tests? My current approach is to duplicate them. Should I continue on this path?Duplicate the test