diff --git a/src/Momento.Sdk/Config/Configurations.cs b/src/Momento.Sdk/Config/Configurations.cs index e7ecd0b8..9a8a716b 100644 --- a/src/Momento.Sdk/Config/Configurations.cs +++ b/src/Momento.Sdk/Config/Configurations.cs @@ -14,8 +14,8 @@ namespace Momento.Sdk.Config; public class Configurations { /// - /// Laptop config provides defaults suitable for a medium-to-high-latency dev environment. Permissive timeouts, retries, potentially - /// a higher number of connections, etc. + /// Laptop config provides defaults suitable for a medium-to-high-latency dev environment. Permissive timeouts, retries, and + /// relaxed latency and throughput targets. /// public class Laptop : Configuration { @@ -25,11 +25,17 @@ private Laptop(ILoggerFactory loggerFactory, IRetryStrategy retryStrategy, ITran } + /// + /// Provides the latest recommended configuration for a Laptop environment. + /// + /// + /// public static Laptop Latest(ILoggerFactory? loggerFactory = null) { var finalLoggerFactory = loggerFactory ?? NullLoggerFactory.Instance; IRetryStrategy retryStrategy = new FixedCountRetryStrategy(finalLoggerFactory, maxAttempts: 3); ITransportStrategy transportStrategy = new StaticTransportStrategy( + loggerFactory: finalLoggerFactory, maxConcurrentRequests: 100, grpcConfig: new StaticGrpcConfiguration(deadline: TimeSpan.FromMilliseconds(15000)) ); @@ -54,11 +60,17 @@ private Default(ILoggerFactory loggerFactory, IRetryStrategy retryStrategy, ITra } + /// + /// Provides the latest recommended configuration for an InRegion environment. + /// + /// + /// public static Default Latest(ILoggerFactory? loggerFactory = null) { var finalLoggerFactory = loggerFactory ?? NullLoggerFactory.Instance; IRetryStrategy retryStrategy = new FixedCountRetryStrategy(finalLoggerFactory, maxAttempts: 3); ITransportStrategy transportStrategy = new StaticTransportStrategy( + loggerFactory: finalLoggerFactory, maxConcurrentRequests: 200, grpcConfig: new StaticGrpcConfiguration(deadline: TimeSpan.FromMilliseconds(1100))); return new Default(finalLoggerFactory, retryStrategy, transportStrategy); @@ -78,11 +90,18 @@ private LowLatency(ILoggerFactory loggerFactory, IRetryStrategy retryStrategy, I } + /// + /// Provides the latest recommended configuration for a low-latency in-region + /// environment. + /// + /// + /// public static LowLatency Latest(ILoggerFactory? loggerFactory = null) { var finalLoggerFactory = loggerFactory ?? NullLoggerFactory.Instance; IRetryStrategy retryStrategy = new FixedCountRetryStrategy(finalLoggerFactory, maxAttempts: 3); ITransportStrategy transportStrategy = new StaticTransportStrategy( + loggerFactory: finalLoggerFactory, maxConcurrentRequests: 20, grpcConfig: new StaticGrpcConfiguration(deadline: TimeSpan.FromMilliseconds(500)) ); diff --git a/src/Momento.Sdk/Config/Middleware/LoggingMiddleware.cs b/src/Momento.Sdk/Config/Middleware/LoggingMiddleware.cs index 06886cd1..fc630600 100644 --- a/src/Momento.Sdk/Config/Middleware/LoggingMiddleware.cs +++ b/src/Momento.Sdk/Config/Middleware/LoggingMiddleware.cs @@ -14,11 +14,16 @@ public class LoggingMiddleware : IMiddleware { private readonly ILogger _logger; + /// + /// + /// + /// public LoggingMiddleware(ILoggerFactory loggerFactory) { _logger = loggerFactory.CreateLogger(); } + /// public async Task> WrapRequest( TRequest request, CallOptions callOptions, diff --git a/src/Momento.Sdk/Config/Middleware/PassThroughMiddleware.cs b/src/Momento.Sdk/Config/Middleware/PassThroughMiddleware.cs index 21e79618..7dc680ff 100644 --- a/src/Momento.Sdk/Config/Middleware/PassThroughMiddleware.cs +++ b/src/Momento.Sdk/Config/Middleware/PassThroughMiddleware.cs @@ -7,15 +7,24 @@ namespace Momento.Sdk.Config.Middleware; +/// +/// No-op middleware. Provided only to illustrate the simplest possible example +/// of a middleware implementation. +/// public class PassThroughMiddleware : IMiddleware { private readonly ILogger _logger; + /// + /// + /// + /// public PassThroughMiddleware(ILoggerFactory loggerFactory) { _logger = loggerFactory.CreateLogger(); } + /// public Task> WrapRequest( TRequest request, CallOptions callOptions, diff --git a/src/Momento.Sdk/Config/Retry/FixedCountRetryStrategy.cs b/src/Momento.Sdk/Config/Retry/FixedCountRetryStrategy.cs index 78031226..d2f9e3ab 100644 --- a/src/Momento.Sdk/Config/Retry/FixedCountRetryStrategy.cs +++ b/src/Momento.Sdk/Config/Retry/FixedCountRetryStrategy.cs @@ -6,14 +6,26 @@ namespace Momento.Sdk.Config.Retry; +/// +/// The most basic retry strategy; simply retries an eligible failed request the specified number of times. +/// public class FixedCountRetryStrategy : IRetryStrategy { private ILoggerFactory _loggerFactory; private ILogger _logger; private readonly IRetryEligibilityStrategy _eligibilityStrategy; + /// + /// The maximum number of attempts that should be made before giving up on an individual request. + /// public int MaxAttempts { get; } + /// + /// + /// + /// + /// The maximum number of attempts that should be made before giving up on an individual request. + /// The strategy used to determine whether a particular failed request is eligible for retry. public FixedCountRetryStrategy(ILoggerFactory loggerFactory, int maxAttempts, IRetryEligibilityStrategy? eligibilityStrategy = null) { _loggerFactory = loggerFactory; @@ -22,11 +34,17 @@ public FixedCountRetryStrategy(ILoggerFactory loggerFactory, int maxAttempts, IR MaxAttempts = maxAttempts; } + /// + /// Copy constructor that updates maxAttempts + /// + /// + /// A new FixedCountRetryStrategy instance with updated maximum number of attempts public FixedCountRetryStrategy WithMaxAttempts(int maxAttempts) { return new(_loggerFactory, maxAttempts, _eligibilityStrategy); } + /// public int? DetermineWhenToRetryRequest(Status grpcStatus, TRequest grpcRequest, int attemptNumber) where TRequest : class { _logger.LogDebug($"Determining whether request is eligible for retry; status code: {grpcStatus.StatusCode}, request type: {grpcRequest.GetType()}, attemptNumber: {attemptNumber}, maxAttempts: {MaxAttempts}"); diff --git a/src/Momento.Sdk/Config/Retry/IRetryEligibilityStrategy.cs b/src/Momento.Sdk/Config/Retry/IRetryEligibilityStrategy.cs index c0ebb211..59484b7a 100644 --- a/src/Momento.Sdk/Config/Retry/IRetryEligibilityStrategy.cs +++ b/src/Momento.Sdk/Config/Retry/IRetryEligibilityStrategy.cs @@ -4,10 +4,20 @@ namespace Momento.Sdk.Config.Retry { + /// + /// Used to determine whether a failed request is eligible for retry. + /// public interface IRetryEligibilityStrategy { - public ILoggerFactory? LoggerFactory { get; } - public IRetryEligibilityStrategy WithLoggerFactory(ILoggerFactory loggerFactory); + /// + /// Given the status code and request object for a failed request, returns + /// true if the request is eligible for retry, false + /// otherwise. + /// + /// + /// The gRPC status of the failed request + /// The original gRPC request object + /// public bool IsEligibleForRetry(Status status, TRequest request) where TRequest : class; } } diff --git a/src/Momento.Sdk/Config/Transport/IGrpcConfiguration.cs b/src/Momento.Sdk/Config/Transport/IGrpcConfiguration.cs index 10bbaf08..a81b671c 100644 --- a/src/Momento.Sdk/Config/Transport/IGrpcConfiguration.cs +++ b/src/Momento.Sdk/Config/Transport/IGrpcConfiguration.cs @@ -20,6 +20,17 @@ public interface IGrpcConfiguration /// public GrpcChannelOptions GrpcChannelOptions { get; } + /// + /// Copy constructor to override the Deadline + /// + /// + /// A new IGrpcConfiguration with the specified Deadline public IGrpcConfiguration WithDeadline(TimeSpan deadline); + + /// + /// Copy constructor to override the channel options + /// + /// + /// A new IGrpcConfiguration with the specified channel options public IGrpcConfiguration WithGrpcChannelOptions(GrpcChannelOptions grpcChannelOptions); } diff --git a/src/Momento.Sdk/Config/Transport/ITransportStrategy.cs b/src/Momento.Sdk/Config/Transport/ITransportStrategy.cs index 03e4c844..e47d9813 100644 --- a/src/Momento.Sdk/Config/Transport/ITransportStrategy.cs +++ b/src/Momento.Sdk/Config/Transport/ITransportStrategy.cs @@ -8,11 +8,35 @@ namespace Momento.Sdk.Config.Transport; /// public interface ITransportStrategy { + /// + /// The maximum number of concurrent requests that the Momento client will + /// allow onto the wire at a given time. + /// public int MaxConcurrentRequests { get; } + /// + /// Configures the low-level gRPC settings for the Momento client's communication + /// with the Momento server. + /// public IGrpcConfiguration GrpcConfig { get; } - public ITransportStrategy WithLoggerFactory(ILoggerFactory loggerFactory); + /// + /// Copy constructor to update the maximum number of concurrent requests. + /// + /// + /// A new ITransportStrategy with the specified maxConccurrentRequests public ITransportStrategy WithMaxConcurrentRequests(int maxConcurrentRequests); + + /// + /// Copy constructor to update the gRPC configuration + /// + /// + /// A new ITransportStrategy with the specified grpcConfig public ITransportStrategy WithGrpcConfig(IGrpcConfiguration grpcConfig); + + /// + /// Copy constructor to update the client timeout + /// + /// + /// A new ITransportStrategy with the specified client timeout public ITransportStrategy WithClientTimeout(TimeSpan clientTimeout); } diff --git a/src/Momento.Sdk/Config/Transport/StaticTransportStrategy.cs b/src/Momento.Sdk/Config/Transport/StaticTransportStrategy.cs index 3f98db8a..74e0f023 100644 --- a/src/Momento.Sdk/Config/Transport/StaticTransportStrategy.cs +++ b/src/Momento.Sdk/Config/Transport/StaticTransportStrategy.cs @@ -5,12 +5,26 @@ namespace Momento.Sdk.Config.Transport; - +/// +/// The simplest way to configure gRPC for the Momento client; specifies static values for +/// request deadline and channel options. +/// public class StaticGrpcConfiguration : IGrpcConfiguration { + /// + /// Maximum amount of time before a request will timeout + /// public TimeSpan Deadline { get; } + /// + /// Customizations to low-level gRPC channel configuration + /// public GrpcChannelOptions GrpcChannelOptions { get; } + /// + /// + /// + /// Maximum amount of time before a request will timeout + /// Customizations to low-level gRPC channel configuration public StaticGrpcConfiguration(TimeSpan deadline, GrpcChannelOptions? grpcChannelOptions = null) { Utils.ArgumentStrictlyPositive(deadline, nameof(deadline)); @@ -18,52 +32,74 @@ public StaticGrpcConfiguration(TimeSpan deadline, GrpcChannelOptions? grpcChanne this.GrpcChannelOptions = grpcChannelOptions ?? new GrpcChannelOptions(); } + /// + /// Copy constructor for overriding the deadline + /// + /// + /// A new GrpcConfiguration with the updated deadline public IGrpcConfiguration WithDeadline(TimeSpan deadline) { return new StaticGrpcConfiguration(deadline, this.GrpcChannelOptions); } + /// + /// Copy constructor for overriding the gRPC channel options + /// + /// + /// A new GrpcConfiguration with the specified channel options public IGrpcConfiguration WithGrpcChannelOptions(GrpcChannelOptions grpcChannelOptions) { return new StaticGrpcConfiguration(this.Deadline, grpcChannelOptions); } } +/// +/// The simplest way to configure the transport layer for the Momento client. +/// Provides static values for the maximum number of concurrent requests and the +/// gRPC configuration. +/// public class StaticTransportStrategy : ITransportStrategy { - public ILoggerFactory? LoggerFactory { get; } + private readonly ILoggerFactory _loggerFactory; + + /// + /// The maximum number of concurrent requests that the Momento client will + /// allow on the wire at one time. + /// public int MaxConcurrentRequests { get; } + /// + /// Configures how Momento client interacts with the Momento service via gRPC + /// public IGrpcConfiguration GrpcConfig { get; } - public StaticTransportStrategy(int maxConcurrentRequests, IGrpcConfiguration grpcConfig, ILoggerFactory? loggerFactory = null) + /// + /// + /// + /// + /// The maximum number of concurrent requests that the Momento client will allow on the wire at one time. + /// Configures how Momento client interacts with the Momento service via gRPC + public StaticTransportStrategy(ILoggerFactory loggerFactory, int maxConcurrentRequests, IGrpcConfiguration grpcConfig) { - LoggerFactory = loggerFactory; + _loggerFactory = loggerFactory; MaxConcurrentRequests = maxConcurrentRequests; GrpcConfig = grpcConfig; } - public StaticTransportStrategy WithLoggerFactory(ILoggerFactory loggerFactory) - { - return new(MaxConcurrentRequests, GrpcConfig, loggerFactory); - } - - ITransportStrategy ITransportStrategy.WithLoggerFactory(ILoggerFactory loggerFactory) - { - return WithLoggerFactory(loggerFactory); - } - + /// public ITransportStrategy WithMaxConcurrentRequests(int maxConcurrentRequests) { - return new StaticTransportStrategy(maxConcurrentRequests, GrpcConfig, LoggerFactory); + return new StaticTransportStrategy(_loggerFactory, maxConcurrentRequests, GrpcConfig); } + /// public ITransportStrategy WithGrpcConfig(IGrpcConfiguration grpcConfig) { - return new StaticTransportStrategy(MaxConcurrentRequests, grpcConfig, LoggerFactory); + return new StaticTransportStrategy(_loggerFactory, MaxConcurrentRequests, grpcConfig); } + /// public ITransportStrategy WithClientTimeout(TimeSpan clientTimeout) { - return new StaticTransportStrategy(MaxConcurrentRequests, GrpcConfig.WithDeadline(clientTimeout), LoggerFactory); + return new StaticTransportStrategy(_loggerFactory, MaxConcurrentRequests, GrpcConfig.WithDeadline(clientTimeout)); } } diff --git a/src/Momento.Sdk/Exceptions/AlreadyExistsException.cs b/src/Momento.Sdk/Exceptions/AlreadyExistsException.cs index 0d9c7ea0..b0ab6a38 100644 --- a/src/Momento.Sdk/Exceptions/AlreadyExistsException.cs +++ b/src/Momento.Sdk/Exceptions/AlreadyExistsException.cs @@ -7,6 +7,7 @@ /// public class AlreadyExistsException : SdkException { + /// public AlreadyExistsException(string message, MomentoErrorTransportDetails transportDetails, Exception? e = null) : base(MomentoErrorCode.ALREADY_EXISTS_ERROR, message, transportDetails, e) { this.MessageWrapper = "A cache with the specified name already exists. To resolve this error, either delete the existing cache and make a new one, or use a different name"; diff --git a/src/Momento.Sdk/Exceptions/AuthenticationException.cs b/src/Momento.Sdk/Exceptions/AuthenticationException.cs index 68a406fc..d5c53cb6 100644 --- a/src/Momento.Sdk/Exceptions/AuthenticationException.cs +++ b/src/Momento.Sdk/Exceptions/AuthenticationException.cs @@ -7,6 +7,7 @@ /// public class AuthenticationException : SdkException { + /// public AuthenticationException(string message, MomentoErrorTransportDetails transportDetails, Exception? e = null) : base(MomentoErrorCode.AUTHENTICATION_ERROR, message, transportDetails, e) { this.MessageWrapper = "Invalid authentication credentials to connect to cache service"; diff --git a/src/Momento.Sdk/Exceptions/BadRequestException.cs b/src/Momento.Sdk/Exceptions/BadRequestException.cs index 43698589..813022ed 100644 --- a/src/Momento.Sdk/Exceptions/BadRequestException.cs +++ b/src/Momento.Sdk/Exceptions/BadRequestException.cs @@ -7,6 +7,7 @@ /// public class BadRequestException : SdkException { + /// public BadRequestException(string message, MomentoErrorTransportDetails transportDetails, Exception? e = null) : base(MomentoErrorCode.BAD_REQUEST_ERROR, message, transportDetails, e) { this.MessageWrapper = "The request was invalid; please contact us at support@momentohq.com"; diff --git a/src/Momento.Sdk/Exceptions/CancelledException.cs b/src/Momento.Sdk/Exceptions/CancelledException.cs index e4bdbd2c..3bbab726 100644 --- a/src/Momento.Sdk/Exceptions/CancelledException.cs +++ b/src/Momento.Sdk/Exceptions/CancelledException.cs @@ -2,6 +2,9 @@ using System; +/// +/// Operation was cancelled. +/// public class CancelledException : SdkException { /// diff --git a/src/Momento.Sdk/Exceptions/FailedPreconditionException.cs b/src/Momento.Sdk/Exceptions/FailedPreconditionException.cs index 8c46862f..192b7389 100644 --- a/src/Momento.Sdk/Exceptions/FailedPreconditionException.cs +++ b/src/Momento.Sdk/Exceptions/FailedPreconditionException.cs @@ -10,6 +10,7 @@ namespace Momento.Sdk.Exceptions; /// public class FailedPreconditionException : SdkException { + /// public FailedPreconditionException(string message, MomentoErrorTransportDetails transportDetails, Exception? e = null) : base(MomentoErrorCode.FAILED_PRECONDITION_ERROR, message, transportDetails, e) { this.MessageWrapper = "System is not in a state required for the operation's execution"; diff --git a/src/Momento.Sdk/Exceptions/InternalServerException.cs b/src/Momento.Sdk/Exceptions/InternalServerException.cs index d2323fa2..2edc500d 100644 --- a/src/Momento.Sdk/Exceptions/InternalServerException.cs +++ b/src/Momento.Sdk/Exceptions/InternalServerException.cs @@ -7,6 +7,7 @@ namespace Momento.Sdk.Exceptions; /// public class InternalServerException : SdkException { + /// public InternalServerException(string message, MomentoErrorTransportDetails transportDetails, Exception? e = null) : base(MomentoErrorCode.INTERNAL_SERVER_ERROR, message, transportDetails, e) { this.MessageWrapper = "An unexpected error occurred while trying to fulfill the request; please contact us at support@momentohq.com"; diff --git a/src/Momento.Sdk/Exceptions/InvalidArgumentException.cs b/src/Momento.Sdk/Exceptions/InvalidArgumentException.cs index 7828a5c5..82aff724 100644 --- a/src/Momento.Sdk/Exceptions/InvalidArgumentException.cs +++ b/src/Momento.Sdk/Exceptions/InvalidArgumentException.cs @@ -7,6 +7,7 @@ namespace Momento.Sdk.Exceptions; /// public class InvalidArgumentException : SdkException { + /// public InvalidArgumentException(string message, MomentoErrorTransportDetails? transportDetails = null, Exception? e = null) : base(MomentoErrorCode.INVALID_ARGUMENT_ERROR, message, transportDetails, e) { this.MessageWrapper = "Invalid argument passed to Momento client"; diff --git a/src/Momento.Sdk/Exceptions/LimitExceededException.cs b/src/Momento.Sdk/Exceptions/LimitExceededException.cs index 86dbe010..40cf3fee 100644 --- a/src/Momento.Sdk/Exceptions/LimitExceededException.cs +++ b/src/Momento.Sdk/Exceptions/LimitExceededException.cs @@ -7,6 +7,7 @@ /// public class LimitExceededException : SdkException { + /// public LimitExceededException(string message, MomentoErrorTransportDetails transportDetails, Exception? 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"; diff --git a/src/Momento.Sdk/Exceptions/NotFoundException.cs b/src/Momento.Sdk/Exceptions/NotFoundException.cs index 748a1bf6..0859be3d 100644 --- a/src/Momento.Sdk/Exceptions/NotFoundException.cs +++ b/src/Momento.Sdk/Exceptions/NotFoundException.cs @@ -7,6 +7,7 @@ /// public class NotFoundException : SdkException { + /// public NotFoundException(string message, MomentoErrorTransportDetails transportDetails, Exception? e = null) : base(MomentoErrorCode.NOT_FOUND_ERROR, message, transportDetails, e) { this.MessageWrapper = "A cache with the specified name does not exist. To resolve this error, make sure you have created the cache before attempting to use it"; diff --git a/src/Momento.Sdk/Exceptions/PermissionDeniedException.cs b/src/Momento.Sdk/Exceptions/PermissionDeniedException.cs index 93d8d0e6..06fa92d3 100644 --- a/src/Momento.Sdk/Exceptions/PermissionDeniedException.cs +++ b/src/Momento.Sdk/Exceptions/PermissionDeniedException.cs @@ -7,6 +7,7 @@ /// public class PermissionDeniedException : SdkException { + /// public PermissionDeniedException(string message, MomentoErrorTransportDetails transportDetails, Exception? e = null) : base(MomentoErrorCode.PERMISSION_ERROR, message, transportDetails, e) { } diff --git a/src/Momento.Sdk/Exceptions/SdkException.cs b/src/Momento.Sdk/Exceptions/SdkException.cs index 33acd7bd..cf3c5ab6 100644 --- a/src/Momento.Sdk/Exceptions/SdkException.cs +++ b/src/Momento.Sdk/Exceptions/SdkException.cs @@ -3,6 +3,10 @@ namespace Momento.Sdk.Exceptions; +/// +/// A list of all available Momento error codes. These can be used to check +/// for specific types of errors on a failure response. +/// public enum MomentoErrorCode { /// @@ -67,12 +71,31 @@ public enum MomentoErrorCode UNKNOWN_ERROR } +/// +/// Captures low-level information about an error, at the gRPC level. Hopefully +/// this is only needed in rare cases, by Momento engineers, for debugging. +/// public class MomentoGrpcErrorDetails { + /// + /// The gRPC status code of the error repsonse + /// public StatusCode Code { get; } + /// + /// Detailed information about the error + /// public string Details { get; } + /// + /// Headers and other information about the error response + /// public Metadata? Metadata { get; set; } + /// + /// + /// + /// + /// + /// public MomentoGrpcErrorDetails(StatusCode code, string details, Metadata? metadata = null) { this.Code = code; @@ -81,22 +104,54 @@ public MomentoGrpcErrorDetails(StatusCode code, string details, Metadata? metada } } +/// +/// Container for low-level error information, including details from the transport layer. +/// public class MomentoErrorTransportDetails { + /// + /// + /// public MomentoGrpcErrorDetails Grpc { get; } + /// + /// + /// + /// public MomentoErrorTransportDetails(MomentoGrpcErrorDetails grpc) { this.Grpc = grpc; } } +/// +/// Base class for all Momento client exceptions +/// public abstract class SdkException : Exception { + /// + /// Enumeration of all possible Momento error types. Should be used in + /// code to distinguish between different types of errors. + /// public MomentoErrorCode ErrorCode { get; } + /// + /// Low-level error details, from the transport layer. Hopefully only needed + /// in rare cases, by Momento engineers, for debugging. + /// public MomentoErrorTransportDetails? TransportDetails { get; } + /// + /// Prefix with basic information about the error class; this will be appended + /// with specific information about the individual error instance at runtime. + /// public string MessageWrapper { get; set; } + /// + /// + /// + /// + /// + /// + /// protected SdkException(MomentoErrorCode errorCode, string message, MomentoErrorTransportDetails? transportDetails = null, Exception? e = null) : base(message, e) { this.ErrorCode = errorCode; diff --git a/src/Momento.Sdk/Exceptions/ServerUnavailableException.cs b/src/Momento.Sdk/Exceptions/ServerUnavailableException.cs index 188995f6..ba8b5a11 100644 --- a/src/Momento.Sdk/Exceptions/ServerUnavailableException.cs +++ b/src/Momento.Sdk/Exceptions/ServerUnavailableException.cs @@ -7,6 +7,7 @@ namespace Momento.Sdk.Exceptions; /// public class ServerUnavailableException : SdkException { + /// public ServerUnavailableException(string message, MomentoErrorTransportDetails transportDetails, Exception? e = null) : base(MomentoErrorCode.SERVER_UNAVAILABLE, message, transportDetails, e) { this.MessageWrapper = "The server was unable to handle the request; consider retrying. If the error persists, please contact us at support@momentohq.com"; diff --git a/src/Momento.Sdk/Exceptions/TimeoutException.cs b/src/Momento.Sdk/Exceptions/TimeoutException.cs index 2af69c8e..fc2a2ee5 100644 --- a/src/Momento.Sdk/Exceptions/TimeoutException.cs +++ b/src/Momento.Sdk/Exceptions/TimeoutException.cs @@ -7,6 +7,7 @@ /// public class TimeoutException : SdkException { + /// public TimeoutException(string message, MomentoErrorTransportDetails transportDetails, Exception? e = null) : base(MomentoErrorCode.TIMEOUT_ERROR, message, transportDetails, e) { this.MessageWrapper = "The client's configured timeout was exceeded; you may need to use a Configuration with more lenient timeouts"; diff --git a/src/Momento.Sdk/Exceptions/UnknownException.cs b/src/Momento.Sdk/Exceptions/UnknownException.cs index 6ac835ae..a0fc4619 100644 --- a/src/Momento.Sdk/Exceptions/UnknownException.cs +++ b/src/Momento.Sdk/Exceptions/UnknownException.cs @@ -7,6 +7,7 @@ namespace Momento.Sdk.Exceptions; /// public class UnknownException : SdkException { + /// public UnknownException(string message, MomentoErrorTransportDetails? transportDetails = null, Exception? e = null) : base(MomentoErrorCode.UNKNOWN_ERROR, message, transportDetails, e) { this.MessageWrapper = "Unknown error has occurred"; diff --git a/src/Momento.Sdk/Exceptions/UnknownServiceException.cs b/src/Momento.Sdk/Exceptions/UnknownServiceException.cs index 3e3ef78c..f9205166 100644 --- a/src/Momento.Sdk/Exceptions/UnknownServiceException.cs +++ b/src/Momento.Sdk/Exceptions/UnknownServiceException.cs @@ -7,6 +7,7 @@ namespace Momento.Sdk.Exceptions; /// public class UnknownServiceException : SdkException { + /// public UnknownServiceException(string message, MomentoErrorTransportDetails transportDetails, Exception? e = null) : base(MomentoErrorCode.BAD_REQUEST_ERROR, message, transportDetails, e) { this.MessageWrapper = "Service returned an unknown response; please contact us at support@momentohq.com"; diff --git a/src/Momento.Sdk/Internal/Retry/DefaultRetryEligibilityStrategy.cs b/src/Momento.Sdk/Internal/Retry/DefaultRetryEligibilityStrategy.cs index f5b04a14..8af57af6 100644 --- a/src/Momento.Sdk/Internal/Retry/DefaultRetryEligibilityStrategy.cs +++ b/src/Momento.Sdk/Internal/Retry/DefaultRetryEligibilityStrategy.cs @@ -9,6 +9,11 @@ namespace Momento.Sdk.Internal.Retry { + /// + /// A retry eligibility strategy that returns true for status codes that + /// are commonly understood to be retry-able (Unavailable, Internal), and + /// for idempotent request types. + /// public class DefaultRetryEligibilityStrategy : IRetryEligibilityStrategy { private readonly HashSet _retryableStatusCodes = new HashSet @@ -38,25 +43,18 @@ public class DefaultRetryEligibilityStrategy : IRetryEligibilityStrategy typeof(_GetRequest) }; - public ILoggerFactory? LoggerFactory { get; } - private readonly ILogger _logger; - public DefaultRetryEligibilityStrategy(ILoggerFactory? loggerFactory) - { - _logger = (loggerFactory ?? NullLoggerFactory.Instance).CreateLogger(); - } - - public DefaultRetryEligibilityStrategy WithLoggerFactory(ILoggerFactory loggerFactory) - { - return new(loggerFactory); - } - - IRetryEligibilityStrategy IRetryEligibilityStrategy.WithLoggerFactory(ILoggerFactory loggerFactory) + /// + /// + /// + /// + public DefaultRetryEligibilityStrategy(ILoggerFactory loggerFactory) { - return WithLoggerFactory(loggerFactory); + _logger = loggerFactory.CreateLogger(); } + /// public bool IsEligibleForRetry(Status status, TRequest request) where TRequest : class { diff --git a/src/Momento.Sdk/docs.xml b/src/Momento.Sdk/docs.xml index 3b932584..26dcf199 100644 --- a/src/Momento.Sdk/docs.xml +++ b/src/Momento.Sdk/docs.xml @@ -45,6 +45,29 @@ + + + + Base class for capturing information about errors that occur during Momento + API calls. + + + message: + + string describing the error. + + + + transportDetails: + + Low-level information about the error, potentially including wire-level + status information. + + + + + +