gas-cache

Cache service for the Gas ecosystem. Provides two gas.CacheProvider implementations —
an in-memory backend for development and testing, and a Valkey (Redis-compatible) backend for production.
Install
go get github.com/gasmod/gas-cache
Backends
| Backend |
Package |
Use case |
| In-memory |
github.com/gasmod/gas-cache/memory |
Development, testing, single-instance deployments |
| Valkey (Redis) |
github.com/gasmod/gas-cache/valkey |
Production, multi-instance deployments |
Both backends implement gas.Service and gas.CacheProvider. The Valkey backend also
implements gas.HealthReporter and gas.ReadyReporter for Kubernetes-style liveness
and readiness probes.
Usage
In-memory backend
package main
import (
"github.com/gasmod/gas"
cachemem "github.com/gasmod/gas-cache/memory"
)
func main() {
app := gas.NewApp(
gas.WithSingletonService[*cachemem.Service](cachemem.New()),
// ...
)
app.Run()
}
With custom configuration:
cfg := cachemem.DefaultConfig()
cfg.Cache.MaxEntries = 10000
cfg.Cache.DefaultTTL = 5 * time.Minute
cfg.Cache.CleanupInterval = 2 * time.Minute
cachemem.New(cachemem.WithConfig(cfg))
Valkey backend
package main
import (
"github.com/gasmod/gas"
cachevk "github.com/gasmod/gas-cache/valkey"
)
func main() {
app := gas.NewApp(
gas.WithSingletonService[*cachevk.Service](cachevk.New()),
// ...
)
app.Run()
}
With custom configuration:
cfg := cachevk.DefaultConfig()
cfg.Cache.Addr = "valkey.internal:6379"
cfg.Cache.Password = "secret"
cfg.Cache.DB = 1
cfg.Cache.ConnRetries = 3
cachevk.New(cachevk.WithConfig(cfg))
Dependency injection
Services receive the cache through gas.CacheProvider via constructor injection:
type Service struct {
cache gas.CacheProvider
}
func New(cache gas.CacheProvider) *Service {
return &Service{cache: cache}
}
func (s *Service) Init() error {
ctx := context.Background()
_ = s.cache.Set(ctx, "hello", []byte("world"), 5*time.Minute)
return nil
}
Direct Valkey client access
For advanced Valkey operations beyond the CacheProvider interface, type-assert to access the underlying client:
type ValkeyProvider interface {
Client() valkey.Client
}
func (s *Service) Init() error {
if vp, ok := s.cache.(ValkeyProvider); ok {
client := vp.Client()
// use client for pub/sub, Lua scripts, etc.
}
return nil
}
Config
If WithConfig is not provided, both backends automatically bind configuration from the gas.ConfigProvider injected
via DI. This lets you drive cache settings from environment variables or a config file without any explicit wiring.
Memory config
| Field |
Default |
Description |
Cache.MaxEntries |
0 |
Max entries (0 = unlimited) |
Cache.CleanupInterval |
1m |
How often expired entries are evicted (0 = disabled) |
Cache.DefaultTTL |
0 |
Default TTL when Set is called with ttl=0 (0 = never expires) |
Valkey config
| Field |
Default |
Description |
Cache.Addr |
localhost:6379 |
Valkey server address (host:port) |
Cache.Password |
|
Authentication password (empty = no auth) |
Cache.DB |
0 |
Database number (0-15) |
Cache.DialTimeout |
5s |
Timeout for establishing new connections |
Cache.WriteTimeout |
3s |
Timeout for write operations and periodic PINGs |
Cache.ConnRetries |
0 |
Number of connection retry attempts (0 = no retries) |
Cache.ConnRetryInterval |
2s |
Base retry interval; doubles each attempt (exp. backoff) |
Testing
The cachetest package provides a mock implementation of gas.CacheProvider:
import "github.com/gasmod/gas-cache/cachetest"
mock := &cachetest.MockCache{}
mock.GetFn = func(ctx context.Context, key string) ([]byte, error) {
return []byte("hello"), nil
}
// pass mock as gas.CacheProvider
// assert calls:
if mock.CallCount("Get") != 1 {
t.Error("expected one Get call")
}
Health and Readiness
The Valkey backend implements gas.HealthReporter and gas.ReadyReporter:
CheckHealth(ctx) — liveness. Returns cache.ErrClosed once the service is closed and
nil otherwise. The valkey-go client reconnects internally, so a transient network
failure is not a liveness failure — a process restart would not help.
CheckReady(ctx) — readiness. Issues a PING against the Valkey server using the
caller's context. Returns an error while the dependency is unreachable so traffic
can be drained until it recovers.
The in-memory backend intentionally does not implement these interfaces: it has no
external dependency and no warmup, so liveness and readiness track the service
lifecycle that the gas framework already manages.
Sentinel Errors
The root cache package defines two sentinel errors used by both backends:
cache.ErrKeyNotFound // returned by Get when the key does not exist or has expired
cache.ErrClosed // returned when an operation is attempted on a closed service