Skip to content

Commit 231cb7a

Browse files
committed
refactor(factory,resolver): wire Redis Cluster backend; split backend resolver to reduce complexity; format and fix lints
1 parent 2aab4f8 commit 231cb7a

File tree

5 files changed

+83
-37
lines changed

5 files changed

+83
-37
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ It ships with a default [historigram stats collector](./pkg/stats/stats.go) and
2121
- Supports multiple, custom backends. Default backends are:
2222
1. [In-memory](./pkg/backend/inmemory.go)
2323
2. [Redis](./pkg/backend/redis.go)
24+
3. [Redis Cluster](./pkg/backend/redis_cluster.go)
2425
- Store items in the cache with a key and expiration duration
2526
- Retrieve items from the cache by their key
2627
- Delete items from the cache by their key

config.go

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ type Config[T backend.IBackendConstrain] struct {
2626
InMemoryOptions []backend.Option[backend.InMemory]
2727
// RedisOptions is a slice of options that can be used to configure the `Redis`.
2828
RedisOptions []backend.Option[backend.Redis]
29+
// RedisClusterOptions is a slice of options to configure the `RedisCluster` backend.
30+
RedisClusterOptions []backend.Option[backend.RedisCluster]
2931
// HyperCacheOptions is a slice of options that can be used to configure `HyperCache`.
3032
HyperCacheOptions []Option[T]
3133
}
@@ -46,9 +48,10 @@ func NewConfig[T backend.IBackendConstrain](backendType string) *Config[T] {
4648
}
4749

4850
return &Config[T]{
49-
BackendType: backendType,
50-
InMemoryOptions: []backend.Option[backend.InMemory]{},
51-
RedisOptions: []backend.Option[backend.Redis]{},
51+
BackendType: backendType,
52+
InMemoryOptions: []backend.Option[backend.InMemory]{},
53+
RedisOptions: []backend.Option[backend.Redis]{},
54+
RedisClusterOptions: []backend.Option[backend.RedisCluster]{},
5255
HyperCacheOptions: []Option[T]{
5356
WithExpirationInterval[T](constants.DefaultExpirationInterval),
5457
WithEvictionAlgorithm[T]("lfu"),

factory.go

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,14 @@ func (RedisBackendConstructor) Create(cfg *Config[backend.Redis]) (backend.IBack
2727
return backend.NewRedis(cfg.RedisOptions...)
2828
}
2929

30+
// RedisClusterBackendConstructor constructs Redis Cluster backends.
31+
type RedisClusterBackendConstructor struct{}
32+
33+
// Create creates a new Redis Cluster backend.
34+
func (RedisClusterBackendConstructor) Create(cfg *Config[backend.RedisCluster]) (backend.IBackend[backend.RedisCluster], error) {
35+
return backend.NewRedisCluster(cfg.RedisClusterOptions...)
36+
}
37+
3038
// BackendManager is a factory for creating HyperCache backend instances.
3139
// It maintains a registry of backend constructors. We store them as any internally,
3240
// and cast to the typed constructor at use site based on T.
@@ -37,8 +45,9 @@ type BackendManager struct {
3745
// getDefaultBackends returns the default set of backend constructors.
3846
func getDefaultBackends() map[string]any {
3947
return map[string]any{
40-
constants.InMemoryBackend: InMemoryBackendConstructor{},
41-
constants.RedisBackend: RedisBackendConstructor{},
48+
constants.InMemoryBackend: InMemoryBackendConstructor{},
49+
constants.RedisBackend: RedisBackendConstructor{},
50+
constants.RedisClusterBackend: RedisClusterBackendConstructor{},
4251
}
4352
}
4453

hypercache.go

Lines changed: 61 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -158,51 +158,80 @@ func resolveBackend[T backend.IBackendConstrain](bm *BackendManager, config *Con
158158

159159
switch config.BackendType {
160160
case constants.InMemoryBackend:
161-
inMemoryConstructor, ok := constructor.(InMemoryBackendConstructor)
162-
if !ok {
163-
return nil, sentinel.ErrInvalidBackendType
164-
}
161+
return resolveInMemoryBackend[T](constructor, config)
162+
case constants.RedisBackend:
163+
return resolveRedisBackend[T](constructor, config)
164+
case constants.RedisClusterBackend:
165+
return resolveRedisClusterBackend[T](constructor, config)
166+
default:
167+
return nil, ewrap.Newf("unknown backend type: %s", config.BackendType)
168+
}
169+
}
165170

166-
cfg, ok := any(config).(*Config[backend.InMemory])
167-
if !ok {
168-
return nil, sentinel.ErrInvalidBackendType
169-
}
171+
// castBackend tries to cast a backend instance of any concrete type to backend.IBackend[T].
172+
func castBackend[T backend.IBackendConstrain](bi any) (backend.IBackend[T], error) {
173+
if b, ok := bi.(backend.IBackend[T]); ok {
174+
return b, nil
175+
}
170176

171-
bi, err := inMemoryConstructor.Create(cfg)
172-
if err != nil {
173-
return nil, err
174-
}
177+
return nil, sentinel.ErrInvalidBackendType
178+
}
175179

176-
if b, ok := any(bi).(backend.IBackend[T]); ok {
177-
return b, nil
178-
}
180+
func resolveInMemoryBackend[T backend.IBackendConstrain](constructor any, cfgAny any) (backend.IBackend[T], error) {
181+
inMemCtor, ok := constructor.(InMemoryBackendConstructor)
182+
if !ok {
183+
return nil, sentinel.ErrInvalidBackendType
184+
}
179185

186+
cfg, ok := cfgAny.(*Config[backend.InMemory])
187+
if !ok {
180188
return nil, sentinel.ErrInvalidBackendType
189+
}
181190

182-
case constants.RedisBackend:
183-
redisConstructor, ok := constructor.(RedisBackendConstructor)
184-
if !ok {
185-
return nil, sentinel.ErrInvalidBackendType
186-
}
191+
bi, err := inMemCtor.Create(cfg)
192+
if err != nil {
193+
return nil, err
194+
}
187195

188-
cfg, ok := any(config).(*Config[backend.Redis])
189-
if !ok {
190-
return nil, sentinel.ErrInvalidBackendType
191-
}
196+
return castBackend[T](bi)
197+
}
192198

193-
bi, err := redisConstructor.Create(cfg)
194-
if err != nil {
195-
return nil, err
196-
}
199+
func resolveRedisBackend[T backend.IBackendConstrain](constructor any, cfgAny any) (backend.IBackend[T], error) {
200+
redisCtor, ok := constructor.(RedisBackendConstructor)
201+
if !ok {
202+
return nil, sentinel.ErrInvalidBackendType
203+
}
197204

198-
if b, ok := any(bi).(backend.IBackend[T]); ok {
199-
return b, nil
200-
}
205+
cfg, ok := cfgAny.(*Config[backend.Redis])
206+
if !ok {
207+
return nil, sentinel.ErrInvalidBackendType
208+
}
209+
210+
bi, err := redisCtor.Create(cfg)
211+
if err != nil {
212+
return nil, err
213+
}
214+
215+
return castBackend[T](bi)
216+
}
201217

218+
func resolveRedisClusterBackend[T backend.IBackendConstrain](constructor any, cfgAny any) (backend.IBackend[T], error) {
219+
clusterCtor, ok := constructor.(RedisClusterBackendConstructor)
220+
if !ok {
202221
return nil, sentinel.ErrInvalidBackendType
203222
}
204223

205-
return nil, ewrap.Newf("unknown backend type: %s", config.BackendType)
224+
cfg, ok := cfgAny.(*Config[backend.RedisCluster])
225+
if !ok {
226+
return nil, sentinel.ErrInvalidBackendType
227+
}
228+
229+
bi, err := clusterCtor.Create(cfg)
230+
if err != nil {
231+
return nil, err
232+
}
233+
234+
return castBackend[T](bi)
206235
}
207236

208237
// newHyperCacheBase builds the base HyperCache instance with default timings and internals.

internal/constants/config.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,4 +27,8 @@ const (
2727
// Constant identifier for the Redis storage backend implementation
2828
// that persists cache data in a Redis database server.
2929
RedisBackend = "redis"
30+
// RedisClusterBackend is the name of the Redis Cluster backend.
31+
// Constant identifier for the Redis Cluster storage backend implementation
32+
// that persists cache data across a Redis Cluster.
33+
RedisClusterBackend = "redis-cluster"
3034
)

0 commit comments

Comments
 (0)