Skip to content

Commit ebf56b6

Browse files
committed
feat: add connection timeout configuration for Redis operations
Signed-off-by: notdu <huudutg@gmail.com>
1 parent 110924a commit ebf56b6

File tree

6 files changed

+21
-6
lines changed

6 files changed

+21
-6
lines changed

README.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@
5454
- [Local Cache](#local-cache)
5555
- [Redis](#redis)
5656
- [Redis type](#redis-type)
57+
- [Connection Timeout](#connection-timeout)
5758
- [Pipelining](#pipelining)
5859
- [One Redis Instance](#one-redis-instance)
5960
- [Two Redis Instances](#two-redis-instances)
@@ -1113,6 +1114,13 @@ The deployment type can be specified with the `REDIS_TYPE` / `REDIS_PERSECOND_TY
11131114
1. "sentinel": A comma separated list with the first string as the master name of the sentinel cluster followed by hostname:port pairs. The list size should be >= 2. The first item is the name of the master and the rest are the sentinels.
11141115
1. "cluster": A comma separated list of hostname:port pairs with all the nodes in the cluster.
11151116

1117+
## Connection Timeout
1118+
1119+
Connection timeout controls the maximum duration for Redis connection establishment, read operations, and write operations.
1120+
1121+
1. `REDIS_TIMEOUT`: sets the timeout for Redis connection and I/O operations. Default: `10s`
1122+
1. `REDIS_PERSECOND_TIMEOUT`: sets the timeout for per-second Redis connection and I/O operations. Default: `10s`
1123+
11161124
## Pipelining
11171125

11181126
By default, for each request, ratelimit will pick up a connection from pool, write multiple redis commands in a single write then reads their responses in a single read. This reduces network delay.

src/redis/cache_impl.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,12 @@ func NewRateLimiterCacheImplFromSettings(s settings.Settings, localCache *freeca
1818
var perSecondPool Client
1919
if s.RedisPerSecond {
2020
perSecondPool = NewClientImpl(srv.Scope().Scope("redis_per_second_pool"), s.RedisPerSecondTls, s.RedisPerSecondAuth, s.RedisPerSecondSocketType,
21-
s.RedisPerSecondType, s.RedisPerSecondUrl, s.RedisPerSecondPoolSize, s.RedisPerSecondPipelineWindow, s.RedisPerSecondPipelineLimit, s.RedisTlsConfig, s.RedisHealthCheckActiveConnection, srv)
21+
s.RedisPerSecondType, s.RedisPerSecondUrl, s.RedisPerSecondPoolSize, s.RedisPerSecondPipelineWindow, s.RedisPerSecondPipelineLimit, s.RedisTlsConfig, s.RedisHealthCheckActiveConnection, srv, s.RedisPerSecondTimeout)
2222
closer.Closers = append(closer.Closers, perSecondPool)
2323
}
2424

2525
otherPool := NewClientImpl(srv.Scope().Scope("redis_pool"), s.RedisTls, s.RedisAuth, s.RedisSocketType, s.RedisType, s.RedisUrl, s.RedisPoolSize,
26-
s.RedisPipelineWindow, s.RedisPipelineLimit, s.RedisTlsConfig, s.RedisHealthCheckActiveConnection, srv)
26+
s.RedisPipelineWindow, s.RedisPipelineLimit, s.RedisTlsConfig, s.RedisHealthCheckActiveConnection, srv, s.RedisTimeout)
2727
closer.Closers = append(closer.Closers, otherPool)
2828

2929
return NewFixedRateLimitCacheImpl(

src/redis/driver_impl.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,13 +72,16 @@ func checkError(err error) {
7272

7373
func NewClientImpl(scope stats.Scope, useTls bool, auth, redisSocketType, redisType, url string, poolSize int,
7474
pipelineWindow time.Duration, pipelineLimit int, tlsConfig *tls.Config, healthCheckActiveConnection bool, srv server.Server,
75+
timeout time.Duration,
7576
) Client {
7677
maskedUrl := utils.MaskCredentialsInUrl(url)
7778
logger.Warnf("connecting to redis on %s with pool size %d", maskedUrl, poolSize)
7879

7980
df := func(network, addr string) (radix.Conn, error) {
8081
var dialOpts []radix.DialOpt
8182

83+
dialOpts = append(dialOpts, radix.DialTimeout(timeout))
84+
8285
if useTls {
8386
dialOpts = append(dialOpts, radix.DialUseTLS(tlsConfig))
8487
}

src/settings/settings.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,10 @@ type Settings struct {
159159
RedisPerSecondPipelineLimit int `envconfig:"REDIS_PERSECOND_PIPELINE_LIMIT" default:"0"`
160160
// Enable healthcheck to check Redis Connection. If there is no active connection, healthcheck failed.
161161
RedisHealthCheckActiveConnection bool `envconfig:"REDIS_HEALTH_CHECK_ACTIVE_CONNECTION" default:"false"`
162+
// RedisTimeout sets the timeout for Redis connection and I/O operations.
163+
RedisTimeout time.Duration `envconfig:"REDIS_TIMEOUT" default:"10s"`
164+
// RedisPerSecondTimeout sets the timeout for per-second Redis connection and I/O operations.
165+
RedisPerSecondTimeout time.Duration `envconfig:"REDIS_PERSECOND_TIMEOUT" default:"10s"`
162166
// Memcache settings
163167
MemcacheHostPort []string `envconfig:"MEMCACHE_HOST_PORT" default:""`
164168
// MemcacheMaxIdleConns sets the maximum number of idle TCP connections per memcached node.

test/redis/bench_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ func BenchmarkParallelDoLimit(b *testing.B) {
4444
return func(b *testing.B) {
4545
statsStore := gostats.NewStore(gostats.NewNullSink(), false)
4646
sm := stats.NewMockStatManager(statsStore)
47-
client := redis.NewClientImpl(statsStore, false, "", "tcp", "single", "127.0.0.1:6379", poolSize, pipelineWindow, pipelineLimit, nil, false, nil)
47+
client := redis.NewClientImpl(statsStore, false, "", "tcp", "single", "127.0.0.1:6379", poolSize, pipelineWindow, pipelineLimit, nil, false, nil, 10*time.Second)
4848
defer client.Close()
4949

5050
cache := redis.NewFixedRateLimitCacheImpl(client, nil, utils.NewTimeSourceImpl(), rand.New(utils.NewLockedSource(time.Now().Unix())), 10, nil, 0.8, "", sm, true)

test/redis/driver_impl_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ func testNewClientImpl(t *testing.T, pipelineWindow time.Duration, pipelineLimit
3838
statsStore := stats.NewStore(stats.NewNullSink(), false)
3939

4040
mkRedisClient := func(auth, addr string) redis.Client {
41-
return redis.NewClientImpl(statsStore, false, auth, "tcp", "single", addr, 1, pipelineWindow, pipelineLimit, nil, false, nil)
41+
return redis.NewClientImpl(statsStore, false, auth, "tcp", "single", addr, 1, pipelineWindow, pipelineLimit, nil, false, nil, 10*time.Second)
4242
}
4343

4444
t.Run("connection refused", func(t *testing.T) {
@@ -131,7 +131,7 @@ func TestDoCmd(t *testing.T) {
131131
statsStore := stats.NewStore(stats.NewNullSink(), false)
132132

133133
mkRedisClient := func(addr string) redis.Client {
134-
return redis.NewClientImpl(statsStore, false, "", "tcp", "single", addr, 1, 0, 0, nil, false, nil)
134+
return redis.NewClientImpl(statsStore, false, "", "tcp", "single", addr, 1, 0, 0, nil, false, nil, 10*time.Second)
135135
}
136136

137137
t.Run("SETGET ok", func(t *testing.T) {
@@ -176,7 +176,7 @@ func testPipeDo(t *testing.T, pipelineWindow time.Duration, pipelineLimit int) f
176176
statsStore := stats.NewStore(stats.NewNullSink(), false)
177177

178178
mkRedisClient := func(addr string) redis.Client {
179-
return redis.NewClientImpl(statsStore, false, "", "tcp", "single", addr, 1, pipelineWindow, pipelineLimit, nil, false, nil)
179+
return redis.NewClientImpl(statsStore, false, "", "tcp", "single", addr, 1, pipelineWindow, pipelineLimit, nil, false, nil, 10*time.Second)
180180
}
181181

182182
t.Run("SETGET ok", func(t *testing.T) {

0 commit comments

Comments
 (0)