Skip to content

Commit

Permalink
move keepalive settings into sockets http handler options
Browse files Browse the repository at this point in the history
  • Loading branch information
anitarua committed Mar 2, 2024
1 parent f90c595 commit 485fe7c
Show file tree
Hide file tree
Showing 9 changed files with 90 additions and 110 deletions.
7 changes: 1 addition & 6 deletions src/Momento.Sdk/Config/AuthConfigurations.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
30 changes: 11 additions & 19 deletions src/Momento.Sdk/Config/Configurations.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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);
}

Expand Down
28 changes: 4 additions & 24 deletions src/Momento.Sdk/Config/TopicConfigurations.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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);
}
Expand Down
30 changes: 0 additions & 30 deletions src/Momento.Sdk/Config/Transport/IGrpcConfiguration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,36 +43,6 @@ public interface IGrpcConfiguration
/// </remarks>
public SocketsHttpHandlerOptions SocketsHttpHandlerOptions { get; }

/// <summary>
/// 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.
/// </summary>
public TimeSpan KeepAlivePingTimeout { get; }

/// <summary>
/// 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.
/// </summary>
public TimeSpan KeepAlivePingDelay { get; }

/// <summary>
/// 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.
/// </summary>
public bool KeepAlivePermitWithoutCalls { get; }

/// <summary>
/// Copy constructor to override the Deadline
/// </summary>
Expand Down
63 changes: 63 additions & 0 deletions src/Momento.Sdk/Config/Transport/SocketsHttpHandlerOptions.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#pragma warning disable 1591
using System;
using System.Net.Http;
using Momento.Sdk.Internal;
namespace Momento.Sdk.Config.Transport;

Expand All @@ -9,6 +10,36 @@ public class SocketsHttpHandlerOptions
public TimeSpan PooledConnectionIdleTimeout { get; } = DefaultPooledConnectionIdleTimeout;
public bool EnableMultipleHttp2Connections { get; } = true;

/// <summary>
/// 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.
/// </summary>
public TimeSpan KeepAlivePingTimeout { get; } = TimeSpan.FromMilliseconds(1000);

/// <summary>
/// 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.
/// </summary>
public TimeSpan KeepAlivePingDelay { get; } = TimeSpan.FromMilliseconds(5000);

/// <summary>
/// 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.
/// </summary>
public bool KeepAlivePermitWithoutCalls { get; } = true;

public SocketsHttpHandlerOptions() { }
public SocketsHttpHandlerOptions(TimeSpan pooledConnectionIdleTimeout) : this(pooledConnectionIdleTimeout, true) { }
public SocketsHttpHandlerOptions(bool enableMultipleHttp2Connections) : this(DefaultPooledConnectionIdleTimeout, enableMultipleHttp2Connections) { }
Expand All @@ -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)
{
Expand All @@ -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)

Check warning on line 111 in src/Momento.Sdk/Config/Transport/SocketsHttpHandlerOptions.cs

View workflow job for this annotation

GitHub Actions / build_csharp (ubuntu-latest, net6.0)

Nullability of type of parameter 'obj' doesn't match overridden member (possibly because of nullability attributes).
{
if (obj == null || GetType() != obj.GetType())
Expand Down
11 changes: 1 addition & 10 deletions src/Momento.Sdk/Config/Transport/StaticTransportStrategy.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,27 +34,18 @@ public class StaticGrpcConfiguration : IGrpcConfiguration
/// <param name="grpcChannelOptions">Customizations to low-level gRPC channel configuration</param>
/// <param name="minNumGrpcChannels">minimum number of gRPC channels to open</param>
/// <param name="socketsHttpHandlerOptions">Customizations to the SocketsHttpHandler</param>
/// <param name="keepAlivePingTimeout">Override the time to wait for a response from a keepalive ping</param>
/// <param name="keepAlivePingDelay">Override how often the client sends keepalive pings the server</param>
/// <param name="keepAlivePermitWithoutCalls">Sets option to send keepalive pings from the client without any outstanding RPCs</param>
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));
this.Deadline = deadline;
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;
}

/// <inheritdoc/>
Expand Down
7 changes: 1 addition & 6 deletions src/Momento.Sdk/Config/VectorIndexConfigurations.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
12 changes: 3 additions & 9 deletions src/Momento.Sdk/Internal/GrpcManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Loading

0 comments on commit 485fe7c

Please sign in to comment.