93 lines
3.6 KiB
Markdown
93 lines
3.6 KiB
Markdown
|
|
# 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.
|