package valkey import ( "context" "fmt" vk "github.com/valkey-io/valkey-go" "code.nochebuena.dev/go/health" "code.nochebuena.dev/go/launcher" "code.nochebuena.dev/go/logz" ) // Provider is the minimal interface for consumers that only need the valkey client. type Provider interface { Client() vk.Client } // Component adds lifecycle management and health check to Provider. type Component interface { launcher.Component health.Checkable Provider } // Config holds Valkey connection settings. type Config struct { Addrs []string `env:"VK_ADDRS,required" envSeparator:","` Password string `env:"VK_PASSWORD"` SelectDB int `env:"VK_DB" envDefault:"0"` CacheSizeEachConn int `env:"VK_CLIENT_CACHE_MB" envDefault:"0"` // MB; 0 = disable } type vkComponent struct { cfg Config logger logz.Logger client vk.Client } // New returns a valkey Component. Call lc.Append(vk) to manage its lifecycle. func New(logger logz.Logger, cfg Config) Component { return &vkComponent{cfg: cfg, logger: logger} } func (v *vkComponent) OnInit() error { opts := vk.ClientOption{ InitAddress: v.cfg.Addrs, Password: v.cfg.Password, SelectDB: v.cfg.SelectDB, } if v.cfg.CacheSizeEachConn > 0 { opts.CacheSizeEachConn = v.cfg.CacheSizeEachConn * 1024 * 1024 } client, err := vk.NewClient(opts) if err != nil { return fmt.Errorf("valkey: failed to create client: %w", err) } v.client = client return nil } func (v *vkComponent) OnStart() error { v.logger.Info("valkey: verifying connection") if v.client == nil { return fmt.Errorf("valkey: client not initialized") } if err := v.client.Do(context.Background(), v.client.B().Ping().Build()).Error(); err != nil { return fmt.Errorf("valkey: ping failed: %w", err) } v.logger.Info("valkey: connected") return nil } func (v *vkComponent) OnStop() error { v.logger.Info("valkey: closing client") if v.client != nil { v.client.Close() } return nil } func (v *vkComponent) Client() vk.Client { return v.client } func (v *vkComponent) HealthCheck(ctx context.Context) error { if v.client == nil { return fmt.Errorf("valkey: client not initialized") } return v.client.Do(ctx, v.client.B().Ping().Build()).Error() } func (v *vkComponent) Name() string { return "valkey" } func (v *vkComponent) Priority() health.Level { return health.LevelDegraded }