diff --git a/src/Momento.Sdk/Config/AuthConfigurations.cs b/src/Momento.Sdk/Config/AuthConfigurations.cs
index 6bfee95b..e560a0a9 100644
--- a/src/Momento.Sdk/Config/AuthConfigurations.cs
+++ b/src/Momento.Sdk/Config/AuthConfigurations.cs
@@ -34,12 +34,7 @@ public static IAuthConfiguration V1(ILoggerFactory? loggerFactory = null)
var finalLoggerFactory = loggerFactory ?? NullLoggerFactory.Instance;
IAuthTransportStrategy transportStrategy = new StaticAuthTransportStrategy(
loggerFactory: finalLoggerFactory,
- grpcConfig: new StaticGrpcConfiguration(
- deadline: TimeSpan.FromMilliseconds(15000),
- keepAlivePermitWithoutCalls: true,
- keepAlivePingDelay: TimeSpan.FromMilliseconds(5000),
- keepAlivePingTimeout: TimeSpan.FromMilliseconds(1000)
- )
+ grpcConfig: new StaticGrpcConfiguration(deadline: TimeSpan.FromMilliseconds(15000))
);
return new Default(finalLoggerFactory, transportStrategy);
}
diff --git a/src/Momento.Sdk/Config/Configurations.cs b/src/Momento.Sdk/Config/Configurations.cs
index 3467f998..370d9ea4 100644
--- a/src/Momento.Sdk/Config/Configurations.cs
+++ b/src/Momento.Sdk/Config/Configurations.cs
@@ -55,12 +55,7 @@ public static IConfiguration V1(ILoggerFactory? loggerFactory = null)
ITransportStrategy transportStrategy = new StaticTransportStrategy(
loggerFactory: finalLoggerFactory,
maxConcurrentRequests: 200, // max of 2 connections https://github.com/momentohq/client-sdk-dotnet/issues/460
- grpcConfig: new StaticGrpcConfiguration(
- deadline: TimeSpan.FromMilliseconds(15000),
- keepAlivePermitWithoutCalls: true,
- keepAlivePingDelay: TimeSpan.FromMilliseconds(5000),
- keepAlivePingTimeout: TimeSpan.FromMilliseconds(1000)
- )
+ grpcConfig: new StaticGrpcConfiguration(deadline: TimeSpan.FromMilliseconds(15000))
);
return new Laptop(finalLoggerFactory, retryStrategy, transportStrategy);
}
@@ -113,12 +108,7 @@ public static IConfiguration V1(ILoggerFactory? loggerFactory = null)
ITransportStrategy transportStrategy = new StaticTransportStrategy(
loggerFactory: finalLoggerFactory,
maxConcurrentRequests: 400, // max of 4 connections https://github.com/momentohq/client-sdk-dotnet/issues/460
- grpcConfig: new StaticGrpcConfiguration(
- deadline: TimeSpan.FromMilliseconds(1100),
- keepAlivePermitWithoutCalls: true,
- keepAlivePingDelay: TimeSpan.FromMilliseconds(5000),
- keepAlivePingTimeout: TimeSpan.FromMilliseconds(1000)
- )
+ grpcConfig: new StaticGrpcConfiguration(deadline: TimeSpan.FromMilliseconds(1100))
);
return new Default(finalLoggerFactory, retryStrategy, transportStrategy);
}
@@ -169,12 +159,7 @@ public static IConfiguration V1(ILoggerFactory? loggerFactory = null)
ITransportStrategy transportStrategy = new StaticTransportStrategy(
loggerFactory: finalLoggerFactory,
maxConcurrentRequests: 20,
- grpcConfig: new StaticGrpcConfiguration(
- deadline: TimeSpan.FromMilliseconds(500),
- keepAlivePermitWithoutCalls: true,
- keepAlivePingDelay: TimeSpan.FromMilliseconds(5000),
- keepAlivePingTimeout: TimeSpan.FromMilliseconds(1000)
- )
+ grpcConfig: new StaticGrpcConfiguration(deadline: TimeSpan.FromMilliseconds(500))
);
return new LowLatency(finalLoggerFactory, retryStrategy, transportStrategy);
}
@@ -207,7 +192,14 @@ public static IConfiguration V1(ILoggerFactory? loggerFactory = null)
{
var config = Default.V1(loggerFactory);
var transportStrategy = config.TransportStrategy.WithSocketsHttpHandlerOptions(
- SocketsHttpHandlerOptions.Of(pooledConnectionIdleTimeout: TimeSpan.FromMinutes(6)));
+ SocketsHttpHandlerOptions.Of(
+ pooledConnectionIdleTimeout: TimeSpan.FromMinutes(6),
+ enableMultipleHttp2Connections: true,
+ keepAlivePingTimeout: System.Threading.Timeout.InfiniteTimeSpan,
+ keepAlivePingDelay: System.Threading.Timeout.InfiniteTimeSpan,
+ keepAlivePermitWithoutCalls: false
+ )
+ );
return config.WithTransportStrategy(transportStrategy);
}
diff --git a/src/Momento.Sdk/Config/TopicConfigurations.cs b/src/Momento.Sdk/Config/TopicConfigurations.cs
index ab866e11..5c9822a0 100644
--- a/src/Momento.Sdk/Config/TopicConfigurations.cs
+++ b/src/Momento.Sdk/Config/TopicConfigurations.cs
@@ -35,12 +35,7 @@ public static ITopicConfiguration latest(ILoggerFactory? loggerFactory = null)
var finalLoggerFactory = loggerFactory ?? NullLoggerFactory.Instance;
ITopicTransportStrategy transportStrategy = new StaticTopicTransportStrategy(
loggerFactory: finalLoggerFactory,
- grpcConfig: new StaticGrpcConfiguration(
- deadline: TimeSpan.FromMilliseconds(15000),
- keepAlivePermitWithoutCalls: true,
- keepAlivePingDelay: TimeSpan.FromMilliseconds(5000),
- keepAlivePingTimeout: TimeSpan.FromMilliseconds(1000)
- )
+ grpcConfig: new StaticGrpcConfiguration(deadline: TimeSpan.FromMilliseconds(15000))
);
return new Laptop(finalLoggerFactory, transportStrategy);
}
@@ -70,12 +65,7 @@ public static ITopicConfiguration latest(ILoggerFactory? loggerFactory = null)
var finalLoggerFactory = loggerFactory ?? NullLoggerFactory.Instance;
ITopicTransportStrategy transportStrategy = new StaticTopicTransportStrategy(
loggerFactory: finalLoggerFactory,
- grpcConfig: new StaticGrpcConfiguration(
- deadline: TimeSpan.FromMilliseconds(15000),
- keepAlivePermitWithoutCalls: true,
- keepAlivePingDelay: TimeSpan.FromMilliseconds(5000),
- keepAlivePingTimeout: TimeSpan.FromMilliseconds(1000)
- )
+ grpcConfig: new StaticGrpcConfiguration(deadline: TimeSpan.FromMilliseconds(15000))
);
return new Mobile(finalLoggerFactory, transportStrategy);
}
@@ -112,12 +102,7 @@ public static ITopicConfiguration Latest(ILoggerFactory? loggerFactory = null)
var finalLoggerFactory = loggerFactory ?? NullLoggerFactory.Instance;
ITopicTransportStrategy transportStrategy = new StaticTopicTransportStrategy(
loggerFactory: finalLoggerFactory,
- grpcConfig: new StaticGrpcConfiguration(
- deadline: TimeSpan.FromMilliseconds(1100),
- keepAlivePermitWithoutCalls: true,
- keepAlivePingDelay: TimeSpan.FromMilliseconds(5000),
- keepAlivePingTimeout: TimeSpan.FromMilliseconds(1000)
- )
+ grpcConfig: new StaticGrpcConfiguration(deadline: TimeSpan.FromMilliseconds(1100))
);
return new Default(finalLoggerFactory, transportStrategy);
}
@@ -151,12 +136,7 @@ public static ITopicConfiguration Latest(ILoggerFactory? loggerFactory = null)
var finalLoggerFactory = loggerFactory ?? NullLoggerFactory.Instance;
ITopicTransportStrategy transportStrategy = new StaticTopicTransportStrategy(
loggerFactory: finalLoggerFactory,
- grpcConfig: new StaticGrpcConfiguration(
- deadline: TimeSpan.FromMilliseconds(500),
- keepAlivePermitWithoutCalls: true,
- keepAlivePingDelay: TimeSpan.FromMilliseconds(5000),
- keepAlivePingTimeout: TimeSpan.FromMilliseconds(1000)
- )
+ grpcConfig: new StaticGrpcConfiguration(deadline: TimeSpan.FromMilliseconds(500))
);
return new LowLatency(finalLoggerFactory, transportStrategy);
}
diff --git a/src/Momento.Sdk/Config/Transport/IGrpcConfiguration.cs b/src/Momento.Sdk/Config/Transport/IGrpcConfiguration.cs
index b825cf89..31e4bf93 100644
--- a/src/Momento.Sdk/Config/Transport/IGrpcConfiguration.cs
+++ b/src/Momento.Sdk/Config/Transport/IGrpcConfiguration.cs
@@ -43,36 +43,6 @@ public interface IGrpcConfiguration
///
public SocketsHttpHandlerOptions SocketsHttpHandlerOptions { get; }
- ///
- /// Override the time to wait for a response from a keepalive or ping.
- /// NOTE: keep-alives are very important for long-lived server environments where there may be periods of time
- /// when the connection is idle. However, they are very problematic for lambda environments where the lambda
- /// runtime is continuously frozen and unfrozen, because the lambda may be frozen before the "ACK" is received
- /// from the server. This can cause the keep-alive to timeout even though the connection is completely healthy.
- /// Therefore, keep-alives should be disabled in lambda and similar environments.
- ///
- public TimeSpan KeepAlivePingTimeout { get; }
-
- ///
- /// After a duration of this time the client/server pings its peer to see if the transport is still alive.
- /// NOTE: keep-alives are very important for long-lived server environments where there may be periods of time
- /// when the connection is idle. However, they are very problematic for lambda environments where the lambda
- /// runtime is continuously frozen and unfrozen, because the lambda may be frozen before the "ACK" is received
- /// from the server. This can cause the keep-alive to timeout even though the connection is completely healthy.
- /// Therefore, keep-alives should be disabled in lambda and similar environments.
- ///
- public TimeSpan KeepAlivePingDelay { get; }
-
- ///
- /// Indicates if it permissible to send keepalive pings from the client without any outstanding streams.
- /// NOTE: keep-alives are very important for long-lived server environments where there may be periods of time
- /// when the connection is idle. However, they are very problematic for lambda environments where the lambda
- /// runtime is continuously frozen and unfrozen, because the lambda may be frozen before the "ACK" is received
- /// from the server. This can cause the keep-alive to timeout even though the connection is completely healthy.
- /// Therefore, keep-alives should be disabled in lambda and similar environments.
- ///
- public bool KeepAlivePermitWithoutCalls { get; }
-
///
/// Copy constructor to override the Deadline
///
diff --git a/src/Momento.Sdk/Config/Transport/SocketsHttpHandlerOptions.cs b/src/Momento.Sdk/Config/Transport/SocketsHttpHandlerOptions.cs
index 4393bcf6..52d8f586 100644
--- a/src/Momento.Sdk/Config/Transport/SocketsHttpHandlerOptions.cs
+++ b/src/Momento.Sdk/Config/Transport/SocketsHttpHandlerOptions.cs
@@ -1,5 +1,6 @@
#pragma warning disable 1591
using System;
+using System.Net.Http;
using Momento.Sdk.Internal;
namespace Momento.Sdk.Config.Transport;
@@ -9,6 +10,36 @@ public class SocketsHttpHandlerOptions
public TimeSpan PooledConnectionIdleTimeout { get; } = DefaultPooledConnectionIdleTimeout;
public bool EnableMultipleHttp2Connections { get; } = true;
+ ///
+ /// Override the time to wait for a response from a keepalive or ping.
+ /// NOTE: keep-alives are very important for long-lived server environments where there may be periods of time
+ /// when the connection is idle. However, they are very problematic for lambda environments where the lambda
+ /// runtime is continuously frozen and unfrozen, because the lambda may be frozen before the "ACK" is received
+ /// from the server. This can cause the keep-alive to timeout even though the connection is completely healthy.
+ /// Therefore, keep-alives should be disabled in lambda and similar environments.
+ ///
+ public TimeSpan KeepAlivePingTimeout { get; } = TimeSpan.FromMilliseconds(1000);
+
+ ///
+ /// After a duration of this time the client/server pings its peer to see if the transport is still alive.
+ /// NOTE: keep-alives are very important for long-lived server environments where there may be periods of time
+ /// when the connection is idle. However, they are very problematic for lambda environments where the lambda
+ /// runtime is continuously frozen and unfrozen, because the lambda may be frozen before the "ACK" is received
+ /// from the server. This can cause the keep-alive to timeout even though the connection is completely healthy.
+ /// Therefore, keep-alives should be disabled in lambda and similar environments.
+ ///
+ public TimeSpan KeepAlivePingDelay { get; } = TimeSpan.FromMilliseconds(5000);
+
+ ///
+ /// Indicates if it permissible to send keepalive pings from the client without any outstanding streams.
+ /// NOTE: keep-alives are very important for long-lived server environments where there may be periods of time
+ /// when the connection is idle. However, they are very problematic for lambda environments where the lambda
+ /// runtime is continuously frozen and unfrozen, because the lambda may be frozen before the "ACK" is received
+ /// from the server. This can cause the keep-alive to timeout even though the connection is completely healthy.
+ /// Therefore, keep-alives should be disabled in lambda and similar environments.
+ ///
+ public bool KeepAlivePermitWithoutCalls { get; } = true;
+
public SocketsHttpHandlerOptions() { }
public SocketsHttpHandlerOptions(TimeSpan pooledConnectionIdleTimeout) : this(pooledConnectionIdleTimeout, true) { }
public SocketsHttpHandlerOptions(bool enableMultipleHttp2Connections) : this(DefaultPooledConnectionIdleTimeout, enableMultipleHttp2Connections) { }
@@ -19,6 +50,21 @@ public SocketsHttpHandlerOptions(TimeSpan pooledConnectionIdleTimeout, bool enab
PooledConnectionIdleTimeout = pooledConnectionIdleTimeout;
EnableMultipleHttp2Connections = enableMultipleHttp2Connections;
}
+ public SocketsHttpHandlerOptions(
+ TimeSpan pooledConnectionIdleTimeout,
+ bool enableMultipleHttp2Connections,
+ TimeSpan keepAlivePingTimeout,
+ TimeSpan keepAlivePingDelay,
+ bool keepAlivePermitWithoutCalls
+ )
+ {
+ Utils.ArgumentStrictlyPositive(pooledConnectionIdleTimeout, nameof(pooledConnectionIdleTimeout));
+ PooledConnectionIdleTimeout = pooledConnectionIdleTimeout;
+ EnableMultipleHttp2Connections = enableMultipleHttp2Connections;
+ KeepAlivePingTimeout = keepAlivePingTimeout;
+ KeepAlivePingDelay = keepAlivePingDelay;
+ KeepAlivePermitWithoutCalls = keepAlivePermitWithoutCalls;
+ }
public SocketsHttpHandlerOptions WithPooledConnectionIdleTimeout(TimeSpan pooledConnectionIdleTimeout)
{
@@ -45,6 +91,23 @@ public static SocketsHttpHandlerOptions Of(TimeSpan pooledConnectionIdleTimeout,
return new SocketsHttpHandlerOptions(pooledConnectionIdleTimeout, enableMultipleHttp2Connections);
}
+ public static SocketsHttpHandlerOptions Of(
+ TimeSpan pooledConnectionIdleTimeout,
+ bool enableMultipleHttp2Connections,
+ TimeSpan keepAlivePingTimeout,
+ TimeSpan keepAlivePingDelay,
+ bool keepAlivePermitWithoutCalls
+ )
+ {
+ return new SocketsHttpHandlerOptions(
+ pooledConnectionIdleTimeout,
+ enableMultipleHttp2Connections,
+ keepAlivePingTimeout,
+ keepAlivePingDelay,
+ keepAlivePermitWithoutCalls
+ );
+ }
+
public override bool Equals(object obj)
{
if (obj == null || GetType() != obj.GetType())
diff --git a/src/Momento.Sdk/Config/Transport/StaticTransportStrategy.cs b/src/Momento.Sdk/Config/Transport/StaticTransportStrategy.cs
index e83790aa..f6cf23e4 100644
--- a/src/Momento.Sdk/Config/Transport/StaticTransportStrategy.cs
+++ b/src/Momento.Sdk/Config/Transport/StaticTransportStrategy.cs
@@ -34,17 +34,11 @@ public class StaticGrpcConfiguration : IGrpcConfiguration
/// Customizations to low-level gRPC channel configuration
/// minimum number of gRPC channels to open
/// Customizations to the SocketsHttpHandler
- /// Override the time to wait for a response from a keepalive ping
- /// Override how often the client sends keepalive pings the server
- /// Sets option to send keepalive pings from the client without any outstanding RPCs
public StaticGrpcConfiguration(
TimeSpan deadline,
GrpcChannelOptions? grpcChannelOptions = null,
int minNumGrpcChannels = 1,
- SocketsHttpHandlerOptions? socketsHttpHandlerOptions = null,
- TimeSpan? keepAlivePingTimeout = null,
- TimeSpan? keepAlivePingDelay = null,
- bool? keepAlivePermitWithoutCalls = null
+ SocketsHttpHandlerOptions? socketsHttpHandlerOptions = null
)
{
Utils.ArgumentStrictlyPositive(deadline, nameof(deadline));
@@ -52,9 +46,6 @@ public StaticGrpcConfiguration(
this.MinNumGrpcChannels = minNumGrpcChannels;
this.GrpcChannelOptions = grpcChannelOptions;
this.SocketsHttpHandlerOptions = socketsHttpHandlerOptions ?? new SocketsHttpHandlerOptions();
- this.KeepAlivePingTimeout = keepAlivePingTimeout ?? System.Threading.Timeout.InfiniteTimeSpan;
- this.KeepAlivePingDelay = keepAlivePingDelay ?? System.Threading.Timeout.InfiniteTimeSpan;
- this.KeepAlivePermitWithoutCalls = keepAlivePermitWithoutCalls ?? false;
}
///
diff --git a/src/Momento.Sdk/Config/VectorIndexConfigurations.cs b/src/Momento.Sdk/Config/VectorIndexConfigurations.cs
index cb9b3b4d..9a3c19d7 100644
--- a/src/Momento.Sdk/Config/VectorIndexConfigurations.cs
+++ b/src/Momento.Sdk/Config/VectorIndexConfigurations.cs
@@ -50,12 +50,7 @@ public static IVectorIndexConfiguration V1(ILoggerFactory? loggerFactory = null)
var finalLoggerFactory = loggerFactory ?? NullLoggerFactory.Instance;
IVectorIndexTransportStrategy transportStrategy = new StaticVectorIndexTransportStrategy(
loggerFactory: finalLoggerFactory,
- grpcConfig: new StaticGrpcConfiguration(
- deadline: TimeSpan.FromMilliseconds(15000),
- keepAlivePermitWithoutCalls: true,
- keepAlivePingDelay: TimeSpan.FromMilliseconds(5000),
- keepAlivePingTimeout: TimeSpan.FromMilliseconds(1000)
- )
+ grpcConfig: new StaticGrpcConfiguration(deadline: TimeSpan.FromMilliseconds(15000))
);
return new Laptop(finalLoggerFactory, transportStrategy);
}
diff --git a/src/Momento.Sdk/Internal/GrpcManager.cs b/src/Momento.Sdk/Internal/GrpcManager.cs
index 82e48266..b646c15a 100644
--- a/src/Momento.Sdk/Internal/GrpcManager.cs
+++ b/src/Momento.Sdk/Internal/GrpcManager.cs
@@ -89,21 +89,15 @@ public GrpcChannelOptions GrpcChannelOptionsFromGrpcConfig(IGrpcConfiguration gr
channelOptions.MaxReceiveMessageSize = grpcConfig.GrpcChannelOptions?.MaxReceiveMessageSize ?? DEFAULT_MAX_MESSAGE_SIZE;
channelOptions.MaxSendMessageSize = grpcConfig.GrpcChannelOptions?.MaxSendMessageSize ?? DEFAULT_MAX_MESSAGE_SIZE;
#if NET5_0_OR_GREATER
- var keepAliveWithoutCalls = System.Net.Http.HttpKeepAlivePingPolicy.WithActiveRequests;
- if (grpcConfig.KeepAlivePermitWithoutCalls == true)
- {
- keepAliveWithoutCalls = System.Net.Http.HttpKeepAlivePingPolicy.Always;
- }
-
if (SocketsHttpHandler.IsSupported) // see: https://github.com/grpc/grpc-dotnet/blob/098dca892a3949ade411c3f2f66003f7b330dfd2/src/Shared/HttpHandlerFactory.cs#L28-L30
{
channelOptions.HttpHandler = new SocketsHttpHandler
{
EnableMultipleHttp2Connections = grpcConfig.SocketsHttpHandlerOptions.EnableMultipleHttp2Connections,
PooledConnectionIdleTimeout = grpcConfig.SocketsHttpHandlerOptions.PooledConnectionIdleTimeout,
- KeepAlivePingTimeout = grpcConfig.KeepAlivePingTimeout,
- KeepAlivePingDelay = grpcConfig.KeepAlivePingDelay,
- KeepAlivePingPolicy = keepAliveWithoutCalls
+ KeepAlivePingTimeout = grpcConfig.SocketsHttpHandlerOptions.KeepAlivePingTimeout,
+ KeepAlivePingDelay = grpcConfig.SocketsHttpHandlerOptions.KeepAlivePingDelay,
+ KeepAlivePingPolicy = grpcConfig.SocketsHttpHandlerOptions.KeepAlivePermitWithoutCalls == true ? System.Net.Http.HttpKeepAlivePingPolicy.Always : System.Net.Http.HttpKeepAlivePingPolicy.WithActiveRequests,
};
}
#elif USE_GRPC_WEB
diff --git a/tests/Unit/Momento.Sdk.Tests/ConfigTest.cs b/tests/Unit/Momento.Sdk.Tests/ConfigTest.cs
index 0dd1c1df..1c783dc9 100644
--- a/tests/Unit/Momento.Sdk.Tests/ConfigTest.cs
+++ b/tests/Unit/Momento.Sdk.Tests/ConfigTest.cs
@@ -25,9 +25,9 @@ public void LambdaConfigDisablesKeepAlive()
{
var config = Configurations.InRegion.Lambda.Latest();
var grpcConfig = config.TransportStrategy.GrpcConfig;
- Assert.Equal(System.Threading.Timeout.InfiniteTimeSpan, grpcConfig.KeepAlivePingTimeout);
- Assert.Equal(System.Threading.Timeout.InfiniteTimeSpan, grpcConfig.KeepAlivePingDelay);
- Assert.False(grpcConfig.KeepAlivePermitWithoutCalls);
+ Assert.Equal(System.Threading.Timeout.InfiniteTimeSpan, grpcConfig.SocketsHttpHandlerOptions.KeepAlivePingTimeout);
+ Assert.Equal(System.Threading.Timeout.InfiniteTimeSpan, grpcConfig.SocketsHttpHandlerOptions.KeepAlivePingDelay);
+ Assert.False(grpcConfig.SocketsHttpHandlerOptions.KeepAlivePermitWithoutCalls);
}
[Fact]
@@ -35,8 +35,8 @@ public void LaptopConfigEnablesKeepAlive()
{
var config = Configurations.Laptop.Latest();
var grpcConfig = config.TransportStrategy.GrpcConfig;
- Assert.Equal(TimeSpan.FromMilliseconds(1000), grpcConfig.KeepAlivePingTimeout);
- Assert.Equal(TimeSpan.FromMilliseconds(5000), grpcConfig.KeepAlivePingDelay);
- Assert.True(grpcConfig.KeepAlivePermitWithoutCalls);
+ Assert.Equal(TimeSpan.FromMilliseconds(1000), grpcConfig.SocketsHttpHandlerOptions.KeepAlivePingTimeout);
+ Assert.Equal(TimeSpan.FromMilliseconds(5000), grpcConfig.SocketsHttpHandlerOptions.KeepAlivePingDelay);
+ Assert.True(grpcConfig.SocketsHttpHandlerOptions.KeepAlivePermitWithoutCalls);
}
}