feat: Valkey cache for search results
- Add internal/cache package using go-redis/v9 (Valkey-compatible) - Cache keys are deterministic SHA-256 hashes of search parameters - Cache wraps the Search() method: check cache → miss → execute → store - Gracefully disabled if Valkey is unreachable or unconfigured - Configurable TTL (default 5m), address, password, and DB index - Environment variable overrides: VALKEY_ADDRESS, VALKEY_PASSWORD, VALKEY_DB, VALKEY_CACHE_TTL - Structured JSON logging via slog throughout cache layer - Refactored service.go: extract executeSearch() from Search() for clarity - Update config.example.toml with [cache] section - Add cache package tests (key generation, nop behavior)
This commit is contained in:
parent
385a7acab7
commit
94322ceff4
9 changed files with 361 additions and 9 deletions
|
|
@ -11,9 +11,10 @@ import (
|
|||
|
||||
// Config is the top-level configuration for the gosearch service.
|
||||
type Config struct {
|
||||
Server ServerConfig `toml:"server"`
|
||||
Server ServerConfig `toml:"server"`
|
||||
Upstream UpstreamConfig `toml:"upstream"`
|
||||
Engines EnginesConfig `toml:"engines"`
|
||||
Engines EnginesConfig `toml:"engines"`
|
||||
Cache CacheConfig `toml:"cache"`
|
||||
}
|
||||
|
||||
type ServerConfig struct {
|
||||
|
|
@ -26,11 +27,19 @@ type UpstreamConfig struct {
|
|||
}
|
||||
|
||||
type EnginesConfig struct {
|
||||
LocalPorted []string `toml:"local_ported"`
|
||||
LocalPorted []string `toml:"local_ported"`
|
||||
Brave BraveConfig `toml:"brave"`
|
||||
Qwant QwantConfig `toml:"qwant"`
|
||||
}
|
||||
|
||||
// CacheConfig holds Valkey/Redis cache settings.
|
||||
type CacheConfig struct {
|
||||
Address string `toml:"address"` // Valkey server address (e.g. "localhost:6379")
|
||||
Password string `toml:"password"` // Auth password (empty = none)
|
||||
DB int `toml:"db"` // Database index (default 0)
|
||||
DefaultTTL string `toml:"default_ttl"` // Cache TTL (e.g. "5m", default "5m")
|
||||
}
|
||||
|
||||
type BraveConfig struct {
|
||||
APIKey string `toml:"api_key"`
|
||||
AccessToken string `toml:"access_token"`
|
||||
|
|
@ -71,6 +80,10 @@ func defaultConfig() *Config {
|
|||
ResultsPerPage: 10,
|
||||
},
|
||||
},
|
||||
Cache: CacheConfig{
|
||||
DB: 0,
|
||||
DefaultTTL: "5m",
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -99,6 +112,18 @@ func applyEnvOverrides(cfg *Config) {
|
|||
if v := os.Getenv("BRAVE_ACCESS_TOKEN"); v != "" {
|
||||
cfg.Engines.Brave.AccessToken = v
|
||||
}
|
||||
if v := os.Getenv("VALKEY_ADDRESS"); v != "" {
|
||||
cfg.Cache.Address = v
|
||||
}
|
||||
if v := os.Getenv("VALKEY_PASSWORD"); v != "" {
|
||||
cfg.Cache.Password = v
|
||||
}
|
||||
if v := os.Getenv("VALKEY_DB"); v != "" {
|
||||
fmt.Sscanf(v, "%d", &cfg.Cache.DB)
|
||||
}
|
||||
if v := os.Getenv("VALKEY_CACHE_TTL"); v != "" {
|
||||
cfg.Cache.DefaultTTL = v
|
||||
}
|
||||
}
|
||||
|
||||
// HTTPTimeout parses the configured timeout string into a time.Duration.
|
||||
|
|
@ -114,6 +139,14 @@ func (c *Config) LocalPortedCSV() string {
|
|||
return strings.Join(c.Engines.LocalPorted, ",")
|
||||
}
|
||||
|
||||
// CacheTTL parses the configured cache TTL string into a time.Duration.
|
||||
func (c *Config) CacheTTL() time.Duration {
|
||||
if d, err := time.ParseDuration(c.Cache.DefaultTTL); err == nil && d > 0 {
|
||||
return d
|
||||
}
|
||||
return 5 * time.Minute
|
||||
}
|
||||
|
||||
func splitCSV(s string) []string {
|
||||
if s == "" {
|
||||
return nil
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue