# valkey Valkey (Redis-compatible) client with launcher lifecycle and health check integration. ## Purpose Manages the lifecycle of a `valkey-go` client: constructs it from config, verifies connectivity at startup, exposes the native client to consumers, and closes it on shutdown. Provides a health check via `PING`. Does not add serialisation, key namespacing, or any caching policy on top of the native client. ## Tier & Dependencies **Tier 3 (infrastructure)** — depends on: - `code.nochebuena.dev/go/health` (Tier 2) - `code.nochebuena.dev/go/launcher` (Tier 2) - `code.nochebuena.dev/go/logz` (Tier 1) - `github.com/valkey-io/valkey-go` (native Valkey client) Does **not** depend on `xerrors` — errors from the valkey-go client are returned as-is. ## Key Design Decisions - **Native client exposure**: `Client() vk.Client` returns the native `valkey-go` client directly. No wrapper, no re-exported command subset. Callers use the full valkey-go command builder API. See ADR-001. - **No serialisation helpers**: The module has no `SetJSON`, `GetJSON`, or similar helpers. Callers marshal and unmarshal their own data. See ADR-002. - **Health priority is Degraded**: `Priority()` returns `health.LevelDegraded`, not `LevelCritical`. A Valkey outage degrades service but should not always halt it, depending on whether the caller falls back to the primary datastore. - **Optional client-side caching**: `Config.CacheSizeEachConn` (in MB) enables valkey-go's built-in client-side cache. Setting it to 0 (the default) disables the cache entirely. - **Duck-typed Logger**: The internal `logger` field is typed as `logz.Logger`, the shared interface from the `logz` module (ADR-001 global pattern). ## Patterns **Lifecycle registration:** ```go vk := valkey.New(logger, cfg) lc.Append(vk) // registers OnInit / OnStart / OnStop ``` **Accessing the client in a repository:** ```go type cacheRepo struct { provider valkey.Provider } func (r *cacheRepo) Get(ctx context.Context, key string) ([]byte, error) { client := r.provider.Client() result := client.Do(ctx, client.B().Get().Key(key).Build()) return result.AsBytes() } ``` **Writing with TTL:** ```go client := provider.Client() cmd := client.B().Set().Key(key).Value(val).Ex(300).Build() if err := client.Do(ctx, cmd).Error(); err != nil { return err } ``` **Health check registration:** ```go health.Register(vkComponent) // satisfies health.Checkable via Name()/Priority()/HealthCheck() ``` ## What to Avoid - Do not add serialisation helpers to this module. Keep marshal/unmarshal in the caller or in a separate cache repository layer. - Do not define custom interfaces that re-export a subset of `vk.Client` methods here. If a consumer needs a minimal testable interface, define it in the consumer package. - Do not call `Client()` before `OnInit` has run — it will return `nil`. - Do not treat `health.LevelDegraded` as if it were `LevelCritical`. Design callers to handle cache misses gracefully rather than depending on Valkey for correctness. ## Testing Notes - Unit tests (`valkey_test.go`) do not require a running Valkey server. They test lifecycle behaviour (nil client safety, name, priority) without real network calls. - `TestComponent_OnInit_InvalidAddr` verifies that an empty address slice does not panic. Whether `OnInit` returns an error depends on the valkey-go implementation; the test documents the accepted behaviour. - Integration tests requiring a live Valkey instance are outside this module and belong in a higher-tier test suite. - `compliance_test.go` (package `valkey_test`) asserts `New(...)` satisfies `Component` at compile time.