From b1a7e80de9cdf157589fdfe8f80c122eb4d47f63 Mon Sep 17 00:00:00 2001 From: anitarua Date: Thu, 31 Oct 2024 11:38:05 -0700 Subject: [PATCH 1/4] chore: improve resource exhausted error message --- .../Exceptions/CacheExceptionMapper.cs | 3 +- .../Exceptions/LimitExceededException.cs | 81 ++++++++++++++++++- 2 files changed, 81 insertions(+), 3 deletions(-) diff --git a/src/Momento.Sdk/Exceptions/CacheExceptionMapper.cs b/src/Momento.Sdk/Exceptions/CacheExceptionMapper.cs index 9ad290ee..3b69d3fe 100644 --- a/src/Momento.Sdk/Exceptions/CacheExceptionMapper.cs +++ b/src/Momento.Sdk/Exceptions/CacheExceptionMapper.cs @@ -1,4 +1,5 @@ using System; +using System.Linq; using System.Threading.Tasks; using Grpc.Core; using Microsoft.Extensions.Logging; @@ -79,7 +80,7 @@ public SdkException Convert(Exception e, Metadata? transportMetadata = null) return new AuthenticationException(ex.Message, transportDetails); case StatusCode.ResourceExhausted: - return new LimitExceededException(ex.Message, transportDetails); + return new LimitExceededException(ex.Message, transportDetails, ex); case StatusCode.NotFound: return new NotFoundException(ex.Message, transportDetails); diff --git a/src/Momento.Sdk/Exceptions/LimitExceededException.cs b/src/Momento.Sdk/Exceptions/LimitExceededException.cs index 40cf3fee..cf4cd9ae 100644 --- a/src/Momento.Sdk/Exceptions/LimitExceededException.cs +++ b/src/Momento.Sdk/Exceptions/LimitExceededException.cs @@ -1,6 +1,7 @@ namespace Momento.Sdk.Exceptions; using System; +using Grpc.Core; /// /// Requested operation couldn't be completed because system limits were hit. @@ -8,8 +9,84 @@ public class LimitExceededException : SdkException { /// - public LimitExceededException(string message, MomentoErrorTransportDetails transportDetails, Exception? e = null) : base(MomentoErrorCode.LIMIT_EXCEEDED_ERROR, message, transportDetails, e) + public LimitExceededException(string message, MomentoErrorTransportDetails transportDetails, RpcException? e = null) : base(MomentoErrorCode.LIMIT_EXCEEDED_ERROR, message, transportDetails, e) { - this.MessageWrapper = "Request rate exceeded the limits for this account. To resolve this error, reduce your request rate, or contact us at support@momentohq.com to request a limit increase"; + var errMetadata = e?.Trailers.Get("err")?.Value; + if (errMetadata != null) { + this.MessageWrapper = errMetadata switch + { + "topic_subscriptions_limit_exceeded" => LimitExceededMessageWrapper.TopicSubscriptionsLimitExceeded.Value, + "operations_rate_limit_exceeded" => LimitExceededMessageWrapper.OperationsRateLimitExceeded.Value, + "throughput_rate_limit_exceeded" => LimitExceededMessageWrapper.ThroughputRateLimitExceeded.Value, + "request_size_limit_exceeded" => LimitExceededMessageWrapper.RequestSizeLimitExceeded.Value, + "item_size_limit_exceeded" => LimitExceededMessageWrapper.ItemSizeLimitExceeded.Value, + "element_size_limit_exceeded" => LimitExceededMessageWrapper.ElementSizeLimitExceeded.Value, + _ => LimitExceededMessageWrapper.UnknownLimitExceeded.Value, + }; + } else { + var lowerCasedMessage = message.ToLower(); + this.MessageWrapper = LimitExceededMessageWrapper.UnknownLimitExceeded.Value; + if (lowerCasedMessage.Contains("subscribers")) { + this.MessageWrapper = LimitExceededMessageWrapper.TopicSubscriptionsLimitExceeded.Value; + } else if (lowerCasedMessage.Contains("operations")) { + this.MessageWrapper = LimitExceededMessageWrapper.OperationsRateLimitExceeded.Value; + } else if (lowerCasedMessage.Contains("throughput")) { + this.MessageWrapper = LimitExceededMessageWrapper.ThroughputRateLimitExceeded.Value; + } else if (lowerCasedMessage.Contains("request limit")) { + this.MessageWrapper = LimitExceededMessageWrapper.RequestSizeLimitExceeded.Value; + } else if (lowerCasedMessage.Contains("item size")) { + this.MessageWrapper = LimitExceededMessageWrapper.ItemSizeLimitExceeded.Value; + } else if (lowerCasedMessage.Contains("element size")) { + this.MessageWrapper = LimitExceededMessageWrapper.ElementSizeLimitExceeded.Value; + } else { + this.MessageWrapper = LimitExceededMessageWrapper.UnknownLimitExceeded.Value; + } + } } } + +/// +/// Provides a specific reason for the limit exceeded error. +/// +public sealed class LimitExceededMessageWrapper +{ + /// + /// Topic subscriptions limit exceeded for this account. + /// + public static readonly LimitExceededMessageWrapper TopicSubscriptionsLimitExceeded = new LimitExceededMessageWrapper("Topic subscriptions limit exceeded for this account"); + /// + /// Request rate limit exceeded for this account. + /// + public static readonly LimitExceededMessageWrapper OperationsRateLimitExceeded = new LimitExceededMessageWrapper("Request rate limit exceeded for this account"); + + /// + /// Bandwidth limit exceeded for this account. + /// + public static readonly LimitExceededMessageWrapper ThroughputRateLimitExceeded = new LimitExceededMessageWrapper("Bandwidth limit exceeded for this account"); + /// + /// Request size limit exceeded for this account. + /// + public static readonly LimitExceededMessageWrapper RequestSizeLimitExceeded = new LimitExceededMessageWrapper("Request size limit exceeded for this account"); + /// + /// Item size limit exceeded for this account. + /// + public static readonly LimitExceededMessageWrapper ItemSizeLimitExceeded = new LimitExceededMessageWrapper("Item size limit exceeded for this account"); + /// + /// Element size limit exceeded for this account. + /// + public static readonly LimitExceededMessageWrapper ElementSizeLimitExceeded = new LimitExceededMessageWrapper("Element size limit exceeded for this account"); + /// + /// Unknown limit exceeded for this account. + /// + public static readonly LimitExceededMessageWrapper UnknownLimitExceeded = new LimitExceededMessageWrapper("Limit exceeded for this account"); + + private LimitExceededMessageWrapper(string value) + { + Value = value; + } + + /// + /// The value of the LimitExceededMessageWrapper. + /// + public string Value { get; private set; } +} \ No newline at end of file From c45a7054c0b4ed4003fd401d48930450402f09ea Mon Sep 17 00:00:00 2001 From: anitarua Date: Thu, 31 Oct 2024 11:40:50 -0700 Subject: [PATCH 2/4] remove unused imports --- src/Momento.Sdk/Exceptions/CacheExceptionMapper.cs | 2 -- src/Momento.Sdk/Exceptions/LimitExceededException.cs | 1 - 2 files changed, 3 deletions(-) diff --git a/src/Momento.Sdk/Exceptions/CacheExceptionMapper.cs b/src/Momento.Sdk/Exceptions/CacheExceptionMapper.cs index 3b69d3fe..5316e98b 100644 --- a/src/Momento.Sdk/Exceptions/CacheExceptionMapper.cs +++ b/src/Momento.Sdk/Exceptions/CacheExceptionMapper.cs @@ -1,6 +1,4 @@ using System; -using System.Linq; -using System.Threading.Tasks; using Grpc.Core; using Microsoft.Extensions.Logging; diff --git a/src/Momento.Sdk/Exceptions/LimitExceededException.cs b/src/Momento.Sdk/Exceptions/LimitExceededException.cs index cf4cd9ae..8a43d13e 100644 --- a/src/Momento.Sdk/Exceptions/LimitExceededException.cs +++ b/src/Momento.Sdk/Exceptions/LimitExceededException.cs @@ -1,6 +1,5 @@ namespace Momento.Sdk.Exceptions; -using System; using Grpc.Core; /// From 0906fca049a169a906d517dbf31c3376f26a8d26 Mon Sep 17 00:00:00 2001 From: anitarua Date: Thu, 31 Oct 2024 13:19:04 -0700 Subject: [PATCH 3/4] make LimitExceededMessageWrapper a static class with static members instead --- .../Exceptions/LimitExceededException.cs | 56 ++++++++----------- 1 file changed, 23 insertions(+), 33 deletions(-) diff --git a/src/Momento.Sdk/Exceptions/LimitExceededException.cs b/src/Momento.Sdk/Exceptions/LimitExceededException.cs index 8a43d13e..7704ca1b 100644 --- a/src/Momento.Sdk/Exceptions/LimitExceededException.cs +++ b/src/Momento.Sdk/Exceptions/LimitExceededException.cs @@ -14,31 +14,31 @@ public LimitExceededException(string message, MomentoErrorTransportDetails trans if (errMetadata != null) { this.MessageWrapper = errMetadata switch { - "topic_subscriptions_limit_exceeded" => LimitExceededMessageWrapper.TopicSubscriptionsLimitExceeded.Value, - "operations_rate_limit_exceeded" => LimitExceededMessageWrapper.OperationsRateLimitExceeded.Value, - "throughput_rate_limit_exceeded" => LimitExceededMessageWrapper.ThroughputRateLimitExceeded.Value, - "request_size_limit_exceeded" => LimitExceededMessageWrapper.RequestSizeLimitExceeded.Value, - "item_size_limit_exceeded" => LimitExceededMessageWrapper.ItemSizeLimitExceeded.Value, - "element_size_limit_exceeded" => LimitExceededMessageWrapper.ElementSizeLimitExceeded.Value, - _ => LimitExceededMessageWrapper.UnknownLimitExceeded.Value, + "topic_subscriptions_limit_exceeded" => LimitExceededMessageWrapper.TopicSubscriptionsLimitExceeded, + "operations_rate_limit_exceeded" => LimitExceededMessageWrapper.OperationsRateLimitExceeded, + "throughput_rate_limit_exceeded" => LimitExceededMessageWrapper.ThroughputRateLimitExceeded, + "request_size_limit_exceeded" => LimitExceededMessageWrapper.RequestSizeLimitExceeded, + "item_size_limit_exceeded" => LimitExceededMessageWrapper.ItemSizeLimitExceeded, + "element_size_limit_exceeded" => LimitExceededMessageWrapper.ElementSizeLimitExceeded, + _ => LimitExceededMessageWrapper.UnknownLimitExceeded, }; } else { var lowerCasedMessage = message.ToLower(); - this.MessageWrapper = LimitExceededMessageWrapper.UnknownLimitExceeded.Value; + this.MessageWrapper = LimitExceededMessageWrapper.UnknownLimitExceeded; if (lowerCasedMessage.Contains("subscribers")) { - this.MessageWrapper = LimitExceededMessageWrapper.TopicSubscriptionsLimitExceeded.Value; + this.MessageWrapper = LimitExceededMessageWrapper.TopicSubscriptionsLimitExceeded; } else if (lowerCasedMessage.Contains("operations")) { - this.MessageWrapper = LimitExceededMessageWrapper.OperationsRateLimitExceeded.Value; + this.MessageWrapper = LimitExceededMessageWrapper.OperationsRateLimitExceeded; } else if (lowerCasedMessage.Contains("throughput")) { - this.MessageWrapper = LimitExceededMessageWrapper.ThroughputRateLimitExceeded.Value; + this.MessageWrapper = LimitExceededMessageWrapper.ThroughputRateLimitExceeded; } else if (lowerCasedMessage.Contains("request limit")) { - this.MessageWrapper = LimitExceededMessageWrapper.RequestSizeLimitExceeded.Value; + this.MessageWrapper = LimitExceededMessageWrapper.RequestSizeLimitExceeded; } else if (lowerCasedMessage.Contains("item size")) { - this.MessageWrapper = LimitExceededMessageWrapper.ItemSizeLimitExceeded.Value; + this.MessageWrapper = LimitExceededMessageWrapper.ItemSizeLimitExceeded; } else if (lowerCasedMessage.Contains("element size")) { - this.MessageWrapper = LimitExceededMessageWrapper.ElementSizeLimitExceeded.Value; + this.MessageWrapper = LimitExceededMessageWrapper.ElementSizeLimitExceeded; } else { - this.MessageWrapper = LimitExceededMessageWrapper.UnknownLimitExceeded.Value; + this.MessageWrapper = LimitExceededMessageWrapper.UnknownLimitExceeded; } } } @@ -47,45 +47,35 @@ public LimitExceededException(string message, MomentoErrorTransportDetails trans /// /// Provides a specific reason for the limit exceeded error. /// -public sealed class LimitExceededMessageWrapper +public static class LimitExceededMessageWrapper { /// /// Topic subscriptions limit exceeded for this account. /// - public static readonly LimitExceededMessageWrapper TopicSubscriptionsLimitExceeded = new LimitExceededMessageWrapper("Topic subscriptions limit exceeded for this account"); + public static string TopicSubscriptionsLimitExceeded = "Topic subscriptions limit exceeded for this account"; /// /// Request rate limit exceeded for this account. /// - public static readonly LimitExceededMessageWrapper OperationsRateLimitExceeded = new LimitExceededMessageWrapper("Request rate limit exceeded for this account"); + public static string OperationsRateLimitExceeded = "Request rate limit exceeded for this account"; /// /// Bandwidth limit exceeded for this account. /// - public static readonly LimitExceededMessageWrapper ThroughputRateLimitExceeded = new LimitExceededMessageWrapper("Bandwidth limit exceeded for this account"); + public static string ThroughputRateLimitExceeded = "Bandwidth limit exceeded for this account"; /// /// Request size limit exceeded for this account. /// - public static readonly LimitExceededMessageWrapper RequestSizeLimitExceeded = new LimitExceededMessageWrapper("Request size limit exceeded for this account"); + public static string RequestSizeLimitExceeded = "Request size limit exceeded for this account"; /// /// Item size limit exceeded for this account. /// - public static readonly LimitExceededMessageWrapper ItemSizeLimitExceeded = new LimitExceededMessageWrapper("Item size limit exceeded for this account"); + public static string ItemSizeLimitExceeded = "Item size limit exceeded for this account"; /// /// Element size limit exceeded for this account. /// - public static readonly LimitExceededMessageWrapper ElementSizeLimitExceeded = new LimitExceededMessageWrapper("Element size limit exceeded for this account"); + public static string ElementSizeLimitExceeded = "Element size limit exceeded for this account"; /// /// Unknown limit exceeded for this account. /// - public static readonly LimitExceededMessageWrapper UnknownLimitExceeded = new LimitExceededMessageWrapper("Limit exceeded for this account"); - - private LimitExceededMessageWrapper(string value) - { - Value = value; - } - - /// - /// The value of the LimitExceededMessageWrapper. - /// - public string Value { get; private set; } + public static string UnknownLimitExceeded = "Limit exceeded for this account"; } \ No newline at end of file From c85867736a6ab3ad72db1bffe39bab10e8c1b02c Mon Sep 17 00:00:00 2001 From: anitarua Date: Thu, 31 Oct 2024 13:26:06 -0700 Subject: [PATCH 4/4] create separate method CreateWithMessageWrapper --- .../Exceptions/CacheExceptionMapper.cs | 2 +- .../Exceptions/LimitExceededException.cs | 33 +++++++++++++------ 2 files changed, 24 insertions(+), 11 deletions(-) diff --git a/src/Momento.Sdk/Exceptions/CacheExceptionMapper.cs b/src/Momento.Sdk/Exceptions/CacheExceptionMapper.cs index 5316e98b..c27b6fd6 100644 --- a/src/Momento.Sdk/Exceptions/CacheExceptionMapper.cs +++ b/src/Momento.Sdk/Exceptions/CacheExceptionMapper.cs @@ -78,7 +78,7 @@ public SdkException Convert(Exception e, Metadata? transportMetadata = null) return new AuthenticationException(ex.Message, transportDetails); case StatusCode.ResourceExhausted: - return new LimitExceededException(ex.Message, transportDetails, ex); + return LimitExceededException.CreateWithMessageWrapper(ex.Message, transportDetails, ex); case StatusCode.NotFound: return new NotFoundException(ex.Message, transportDetails); diff --git a/src/Momento.Sdk/Exceptions/LimitExceededException.cs b/src/Momento.Sdk/Exceptions/LimitExceededException.cs index 7704ca1b..aa99ced0 100644 --- a/src/Momento.Sdk/Exceptions/LimitExceededException.cs +++ b/src/Momento.Sdk/Exceptions/LimitExceededException.cs @@ -8,11 +8,23 @@ public class LimitExceededException : SdkException { /// - public LimitExceededException(string message, MomentoErrorTransportDetails transportDetails, RpcException? e = null) : base(MomentoErrorCode.LIMIT_EXCEEDED_ERROR, message, transportDetails, e) + public LimitExceededException(string messageWrapper, string message, MomentoErrorTransportDetails transportDetails, RpcException? e = null) : base(MomentoErrorCode.LIMIT_EXCEEDED_ERROR, message, transportDetails, e) { + this.MessageWrapper = messageWrapper; + } + + /// + /// Creates a LimitExceededException with a message wrapper that specifies the limit that was exceeded. + /// + /// + /// + /// + /// + public static LimitExceededException CreateWithMessageWrapper(string message, MomentoErrorTransportDetails transportDetails, RpcException? e = null) { + var messageWrapper = LimitExceededMessageWrapper.UnknownLimitExceeded; var errMetadata = e?.Trailers.Get("err")?.Value; if (errMetadata != null) { - this.MessageWrapper = errMetadata switch + messageWrapper = errMetadata switch { "topic_subscriptions_limit_exceeded" => LimitExceededMessageWrapper.TopicSubscriptionsLimitExceeded, "operations_rate_limit_exceeded" => LimitExceededMessageWrapper.OperationsRateLimitExceeded, @@ -24,23 +36,24 @@ public LimitExceededException(string message, MomentoErrorTransportDetails trans }; } else { var lowerCasedMessage = message.ToLower(); - this.MessageWrapper = LimitExceededMessageWrapper.UnknownLimitExceeded; if (lowerCasedMessage.Contains("subscribers")) { - this.MessageWrapper = LimitExceededMessageWrapper.TopicSubscriptionsLimitExceeded; + messageWrapper = LimitExceededMessageWrapper.TopicSubscriptionsLimitExceeded; } else if (lowerCasedMessage.Contains("operations")) { - this.MessageWrapper = LimitExceededMessageWrapper.OperationsRateLimitExceeded; + messageWrapper = LimitExceededMessageWrapper.OperationsRateLimitExceeded; } else if (lowerCasedMessage.Contains("throughput")) { - this.MessageWrapper = LimitExceededMessageWrapper.ThroughputRateLimitExceeded; + messageWrapper = LimitExceededMessageWrapper.ThroughputRateLimitExceeded; } else if (lowerCasedMessage.Contains("request limit")) { - this.MessageWrapper = LimitExceededMessageWrapper.RequestSizeLimitExceeded; + messageWrapper = LimitExceededMessageWrapper.RequestSizeLimitExceeded; } else if (lowerCasedMessage.Contains("item size")) { - this.MessageWrapper = LimitExceededMessageWrapper.ItemSizeLimitExceeded; + messageWrapper = LimitExceededMessageWrapper.ItemSizeLimitExceeded; } else if (lowerCasedMessage.Contains("element size")) { - this.MessageWrapper = LimitExceededMessageWrapper.ElementSizeLimitExceeded; + messageWrapper = LimitExceededMessageWrapper.ElementSizeLimitExceeded; } else { - this.MessageWrapper = LimitExceededMessageWrapper.UnknownLimitExceeded; + messageWrapper = LimitExceededMessageWrapper.UnknownLimitExceeded; } } + + return new LimitExceededException(messageWrapper, message, transportDetails, e); } }