-
Notifications
You must be signed in to change notification settings - Fork 0
perf(redis): tune client pool config #24
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -7,6 +7,7 @@ import ( | |
| "fmt" | ||
| "time" | ||
|
|
||
| "github.com/garrettladley/pkgsite-mcp/internal/config" | ||
| "github.com/garrettladley/pkgsite-mcp/internal/kv" | ||
| "github.com/redis/go-redis/extra/redisotel/v9" | ||
| goredis "github.com/redis/go-redis/v9" | ||
|
|
@@ -23,18 +24,19 @@ type Store struct { | |
|
|
||
| var _ kv.Store = (*Store)(nil) | ||
|
|
||
| func New(redisURL string) (kv.Store, error) { | ||
| if redisURL == "" { | ||
| func New(cfg config.KV) (kv.Store, error) { | ||
| if cfg.RedisURL == "" { | ||
| return nil, nil | ||
| } | ||
| return NewStore(redisURL) | ||
| return NewStore(cfg) | ||
| } | ||
|
|
||
| func NewStore(redisURL string) (*Store, error) { | ||
| opts, err := goredis.ParseURL(redisURL) | ||
| func NewStore(cfg config.KV) (*Store, error) { | ||
| opts, err := goredis.ParseURL(cfg.RedisURL) | ||
| if err != nil { | ||
| return nil, err | ||
| } | ||
| applyOptions(opts, cfg) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| client := goredis.NewClient(opts) | ||
| if err := redisotel.InstrumentTracing(client); err != nil { | ||
| return nil, err | ||
|
|
@@ -45,6 +47,19 @@ func NewStore(redisURL string) (*Store, error) { | |
| return &Store{client: client}, nil | ||
| } | ||
|
|
||
| func applyOptions(opts *goredis.Options, cfg config.KV) { | ||
| opts.DisableIdentity = cfg.RedisDisableIdentity | ||
| opts.PoolSize = cfg.RedisPool.Size | ||
| opts.MinIdleConns = cfg.RedisPool.MinIdleConns | ||
| opts.MaxIdleConns = cfg.RedisPool.MaxIdleConns | ||
| opts.MaxActiveConns = cfg.RedisPool.MaxActiveConns | ||
| opts.PoolTimeout = cfg.RedisPool.Timeout | ||
| opts.DialTimeout = cfg.RedisTimeouts.Dial | ||
| opts.ReadTimeout = cfg.RedisTimeouts.Read | ||
| opts.WriteTimeout = cfg.RedisTimeouts.Write | ||
| opts.ConnMaxIdleTime = cfg.RedisConnMaxIdle | ||
| } | ||
|
|
||
| func (s *Store) Get(ctx context.Context, key string) ([]byte, error) { | ||
| value, err := s.client.Get(ctx, key).Bytes() | ||
| if errors.Is(err, goredis.Nil) { | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,64 @@ | ||
| package redis | ||
|
|
||
| import ( | ||
| "testing" | ||
| "time" | ||
|
|
||
| "github.com/garrettladley/pkgsite-mcp/internal/config" | ||
| goredis "github.com/redis/go-redis/v9" | ||
| ) | ||
|
|
||
| func TestApplyOptions(t *testing.T) { | ||
| t.Parallel() | ||
|
|
||
| cfg := config.KV{ | ||
| RedisPool: config.RedisPool{ | ||
| Size: 4, | ||
| MinIdleConns: 2, | ||
| MaxIdleConns: 4, | ||
| MaxActiveConns: 8, | ||
| Timeout: 250 * time.Millisecond, | ||
| }, | ||
| RedisTimeouts: config.RedisTimeouts{ | ||
| Dial: time.Second, | ||
| Read: 750 * time.Millisecond, | ||
| Write: 750 * time.Millisecond, | ||
| }, | ||
| RedisConnMaxIdle: 10 * time.Minute, | ||
| RedisDisableIdentity: true, | ||
| } | ||
| opts := &goredis.Options{} | ||
|
|
||
| applyOptions(opts, cfg) | ||
|
|
||
| if !opts.DisableIdentity { | ||
| t.Fatal("DisableIdentity = false, want true") | ||
| } | ||
| if opts.PoolSize != 4 { | ||
| t.Fatalf("PoolSize = %d, want 4", opts.PoolSize) | ||
| } | ||
| if opts.MinIdleConns != 2 { | ||
| t.Fatalf("MinIdleConns = %d, want 2", opts.MinIdleConns) | ||
| } | ||
| if opts.MaxIdleConns != 4 { | ||
| t.Fatalf("MaxIdleConns = %d, want 4", opts.MaxIdleConns) | ||
| } | ||
| if opts.MaxActiveConns != 8 { | ||
| t.Fatalf("MaxActiveConns = %d, want 8", opts.MaxActiveConns) | ||
| } | ||
| if opts.PoolTimeout != 250*time.Millisecond { | ||
| t.Fatalf("PoolTimeout = %s, want 250ms", opts.PoolTimeout) | ||
| } | ||
| if opts.DialTimeout != time.Second { | ||
| t.Fatalf("DialTimeout = %s, want 1s", opts.DialTimeout) | ||
| } | ||
| if opts.ReadTimeout != 750*time.Millisecond { | ||
| t.Fatalf("ReadTimeout = %s, want 750ms", opts.ReadTimeout) | ||
| } | ||
| if opts.WriteTimeout != 750*time.Millisecond { | ||
| t.Fatalf("WriteTimeout = %s, want 750ms", opts.WriteTimeout) | ||
| } | ||
| if opts.ConnMaxIdleTime != 10*time.Minute { | ||
| t.Fatalf("ConnMaxIdleTime = %s, want 10m", opts.ConnMaxIdleTime) | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
RedisDisableIdentitydefaults totrue, changing existing behaviorBefore this PR, no
DisableIdentityoverride existed, so go-redis defaulted tofalse(identity enabled). Setting the default totruesilently disables theCLIENT SETNAME/CLIENT INFOhandshake on every new connection for all existing deployments that don't setKV_REDIS_DISABLE_IDENTITY. This makes Redis-side connection monitoring invisible by default. Defaulting tofalse(the go-redis default) preserves backward-compatible behavior; operators who want to suppress identity for performance can opt-in explicitly.