cache

package
v0.18.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 5, 2026 License: MIT Imports: 6 Imported by: 0

README

HotPlex Cache Layer

可插拔缓存层,支持多种后端实现,默认为 No-Op(无操作)以保持向后兼容。

设计目标

  1. 向后兼容: 默认 No-Op 实现,不影响现有功能
  2. 可扩展性: 清晰的接口设计,易于添加新后端
  3. 统一 API: 所有后端使用相同的接口
  4. 类型安全: 完整的类型定义和错误处理

架构

┌─────────────────────────────────────────┐
│           Application Layer             │
├─────────────────────────────────────────┤
│            Cache Helper                 │
│  (GetJSON, SetJSON, GetOrCompute)       │
├─────────────────────────────────────────┤
│           Cache Interface               │
│  (Get, Set, Delete, Exists, Clear)      │
├─────────────────────────────────────────┤
│         Backend Implementations         │
│  ┌─────────┬─────────┬─────────────┐   │
│  │ NoOp    │ Memory  │ Redis       │   │
│  │ (Default)│ (TODO)  │ (TODO)      │   │
│  └─────────┴─────────┴─────────────┘   │
└─────────────────────────────────────────┘

核心接口

Cache

所有缓存后端必须实现的基本接口:

type Cache interface {
    Get(ctx context.Context, key string) (*CacheEntry, error)
    Set(ctx context.Context, key string, value []byte, opts ...CacheOption) error
    Delete(ctx context.Context, key string) error
    Exists(ctx context.Context, key string) (bool, error)
    Clear(ctx context.Context) error
    Close() error
    Name() string
}
TaggedCache

支持标签操作的扩展接口:

type TaggedCache interface {
    Cache
    DeleteByTag(ctx context.Context, tag string) error
    ListKeysByTag(ctx context.Context, tag string) ([]string, error)
}
StatsProvider

提供统计信息的接口:

type StatsProvider interface {
    GetStats(ctx context.Context) (*CacheStats, error)
}

使用示例

基础使用
import "github.com/hrygo/hotplex/cache"

// 使用全局缓存(默认 No-Op)
ctx := context.Background()
err := cache.Set(ctx, "key", []byte("value"), cache.WithTTL(1*time.Hour))
entry, err := cache.Get(ctx, "key")
JSON 数据
type MyData struct {
    Name  string
    Value int
}

data := &MyData{Name: "test", Value: 42}

// 存储 JSON
err := cache.SetJSON(ctx, "my-key", data, cache.WithTTL(cache.TTLMedium))

// 读取 JSON
var result MyData
err := cache.GetJSON(ctx, "my-key", &result)
GetOrCompute 模式
value, err := cache.GetOrCompute(ctx, "expensive-key", 
    func() ([]byte, error) {
        // 执行昂贵操作
        return computeExpensiveResult()
    },
    cache.WithTTL(cache.TTLLong),
)
自定义缓存后端
// 1. 实现 Cache 接口
type MyCustomCache struct {
    // 后端特定字段
}

func (c *MyCustomCache) Get(ctx context.Context, key string) (*CacheEntry, error) {
    // 实现获取逻辑
}

func (c *MyCustomCache) Set(ctx context.Context, key string, value []byte, opts ...CacheOption) error {
    // 实现设置逻辑
}

// ... 实现其他方法

// 2. 注册为全局缓存
cache.SetGlobalCache(&MyCustomCache{})
使用 CacheHelper
helper := cache.NewCacheHelper(myCache)

// JSON 操作
err := helper.SetJSON(ctx, "key", data, cache.WithTTL(1*time.Hour))
err := helper.GetJSON(ctx, "key", &result)

// GetOrCompute
data, err := helper.GetOrCompute(ctx, "key", computeFunc, opts...)

缓存键 helpers

// Prompt 缓存
key := cache.PromptCacheKey(sessionID, prompt)

// Response 缓存
key := cache.ResponseCacheKey(sessionID, prompt, model)

// Session 上下文缓存
key := cache.SessionCacheKey(sessionID)

// Tool 结果缓存
key := cache.ToolCacheKey("bash", args)

TTL 预设

cache.TTLShort      // 5 分钟
cache.TTLMedium     // 1 小时
cache.TTLLong       // 24 小时
cache.TTLPermanent  // 永久(无过期)

统计信息

stats, err := cache.GetGlobalCache().(cache.StatsProvider).GetStats(ctx)
fmt.Printf("Hit Ratio: %.2f%%\n", stats.HitRatio() * 100)
fmt.Printf("Hits: %d, Misses: %d\n", stats.Hits, stats.Misses)

未来扩展

计划实现的后端
  1. MemoryCache: 进程内 LRU 缓存
  2. RedisCache: Redis 后端,支持分布式缓存
  3. SemanticCache: 基于向量相似度的语义缓存
扩展点
  • 实现 Cache 接口添加新后端
  • 实现 TaggedCache 接口添加标签支持
  • 实现 StatsProvider 接口添加统计功能

注意事项

  1. 线程安全: 所有实现必须保证并发安全
  2. 错误处理: 返回明确的错误类型(如 ErrCacheMiss
  3. 上下文: 所有操作支持 context.Context 用于取消和超时
  4. 序列化: JSON 辅助函数使用 encoding/json,自定义后端可优化

测试

go test ./cache/... -v

性能考虑

  • No-Op 实现零开销
  • Memory 缓存应避免大对象
  • Redis 缓存注意网络连接池
  • 合理设置 TTL 避免内存泄漏

Documentation

Overview

Package cache provides a pluggable caching layer for HotPlex. It supports multiple cache backends (memory, redis, semantic) with a unified interface. Default implementation is noop (no-op) for backward compatibility.

Index

Constants

View Source
const (
	// KeyPrefixPrompt is the prefix for prompt cache keys
	KeyPrefixPrompt = "prompt:"

	// KeyPrefixResponse is the prefix for response cache keys
	KeyPrefixResponse = "response:"

	// KeyPrefixSession is the prefix for session context cache keys
	KeyPrefixSession = "session:"

	// KeyPrefixTool is the prefix for tool result cache keys
	KeyPrefixTool = "tool:"
)

Common cache key prefixes for HotPlex

Variables

View Source
var (
	// TTLShort is for short-lived cache entries (5 minutes)
	TTLShort = 5 * time.Minute

	// TTLMedium is for medium-lived cache entries (1 hour)
	TTLMedium = 1 * time.Hour

	// TTLLong is for long-lived cache entries (24 hours)
	TTLLong = 24 * time.Hour

	// TTLPermanent is for permanent cache entries (no expiration)
	TTLPermanent = time.Duration(0)
)

Common TTL presets

View Source
var ErrCacheMiss = fmt.Errorf("cache miss")

ErrCacheMiss indicates that the requested key was not found in the cache.

Functions

func ComputeKey

func ComputeKey(parts ...string) string

ComputeKey generates a cache key from input data using SHA256. This is useful for caching API responses, prompts, etc.

func Delete

func Delete(ctx context.Context, key string) error

Delete is a convenience function to delete a value from the default cache.

func GetJSON

func GetJSON(ctx context.Context, key string, out interface{}) error

GetJSON is a convenience function to get a JSON value from the default cache.

func GetOrCompute

func GetOrCompute(ctx context.Context, key string, compute func() ([]byte, error), opts ...CacheOption) ([]byte, error)

GetOrCompute is a convenience function to get or compute a value from the default cache.

func PromptCacheKey

func PromptCacheKey(sessionID, prompt string) string

PromptCacheKey generates a cache key for a prompt.

func ResponseCacheKey

func ResponseCacheKey(sessionID, prompt string, model string) string

ResponseCacheKey generates a cache key for a response.

func SessionCacheKey

func SessionCacheKey(sessionID string) string

SessionCacheKey generates a cache key for session context.

func Set

func Set(ctx context.Context, key string, value []byte, opts ...CacheOption) error

Set is a convenience function to set a value in the default cache.

func SetGlobalCache

func SetGlobalCache(cache Cache)

SetGlobalCache sets the global cache instance. This should be called during application initialization.

func SetJSON

func SetJSON(ctx context.Context, key string, value interface{}, opts ...CacheOption) error

SetJSON is a convenience function to set a JSON value in the default cache.

func ToolCacheKey

func ToolCacheKey(toolName string, args map[string]interface{}) string

ToolCacheKey generates a cache key for tool results.

Types

type Cache

type Cache interface {
	// Get retrieves a value from the cache by key.
	// Returns nil if the key doesn't exist or has expired.
	Get(ctx context.Context, key string) (*CacheEntry, error)

	// Set stores a value in the cache with the given key.
	// Options can specify TTL, tags, and metadata.
	Set(ctx context.Context, key string, value []byte, opts ...CacheOption) error

	// Delete removes a value from the cache by key.
	// Returns nil if the key doesn't exist (idempotent).
	Delete(ctx context.Context, key string) error

	// Exists checks if a key exists in the cache (without checking expiration).
	Exists(ctx context.Context, key string) (bool, error)

	// Clear removes all cache entries.
	// Use with caution in production.
	Clear(ctx context.Context) error

	// Close gracefully shuts down the cache backend.
	Close() error

	// Name returns the cache backend name for logging.
	Name() string
}

Cache is the main cache interface that all backends must implement.

func DefaultCache

func DefaultCache() Cache

DefaultCache is an alias for GetGlobalCache for convenience.

func GetGlobalCache

func GetGlobalCache() Cache

GetGlobalCache returns the global cache instance.

type CacheEntry

type CacheEntry struct {
	// Key is the unique identifier for this entry
	Key string

	// Value is the cached data
	Value []byte

	// CreatedAt is the timestamp when this entry was created
	CreatedAt time.Time

	// ExpiresAt is the timestamp when this entry expires (zero means no expiration)
	ExpiresAt time.Time

	// Metadata contains optional metadata about the cached entry
	Metadata map[string]string
}

CacheEntry represents a cached item with metadata.

func Get

func Get(ctx context.Context, key string) (*CacheEntry, error)

Get is a convenience function to get a value from the default cache.

func (*CacheEntry) IsExpired

func (e *CacheEntry) IsExpired() bool

IsExpired returns true if the cache entry has expired.

type CacheHelper

type CacheHelper struct {
	// contains filtered or unexported fields
}

CacheHelper provides convenient methods for common caching operations.

func NewCacheHelper

func NewCacheHelper(cache Cache) *CacheHelper

NewCacheHelper creates a new cache helper.

func (*CacheHelper) DeletePrefix

func (h *CacheHelper) DeletePrefix(ctx context.Context, prefix string) error

DeletePrefix deletes all keys with the given prefix.

func (*CacheHelper) GetJSON

func (h *CacheHelper) GetJSON(ctx context.Context, key string, out interface{}) error

GetJSON retrieves a JSON value from the cache and unmarshals it.

func (*CacheHelper) GetOrCompute

func (h *CacheHelper) GetOrCompute(ctx context.Context, key string, compute func() ([]byte, error), opts ...CacheOption) ([]byte, error)

GetOrCompute gets a value from cache, or computes and caches it if missing.

func (*CacheHelper) GetOrComputeJSON

func (h *CacheHelper) GetOrComputeJSON(ctx context.Context, key string, compute func() (interface{}, error), out interface{}, opts ...CacheOption) error

GetOrComputeJSON gets a JSON value from cache, or computes and caches it if missing.

func (*CacheHelper) SetJSON

func (h *CacheHelper) SetJSON(ctx context.Context, key string, value interface{}, opts ...CacheOption) error

SetJSON marshals a value to JSON and stores it in the cache.

type CacheOption

type CacheOption func(*CacheOptions)

CacheOption is a functional option for CacheOptions.

func WithMetadata

func WithMetadata(metadata map[string]string) CacheOption

WithMetadata sets metadata for cache entries.

func WithSkipCache

func WithSkipCache(skip bool) CacheOption

WithSkipCache skips caching for this operation.

func WithTTL

func WithTTL(ttl time.Duration) CacheOption

WithTTL sets the TTL for cache entries.

func WithTags

func WithTags(tags ...string) CacheOption

WithTags sets tags for cache entries.

type CacheOptions

type CacheOptions struct {
	// TTL is the time-to-live for the cache entry
	TTL time.Duration

	// Tags are optional tags for grouping cache entries
	Tags []string

	// Metadata is optional metadata to store with the entry
	Metadata map[string]string

	// SkipCache indicates whether to skip caching for this operation
	SkipCache bool
}

CacheOptions configures cache operations.

type CacheStats

type CacheStats struct {
	// Hits is the number of cache hits
	Hits int64

	// Misses is the number of cache misses
	Misses int64

	// Size is the current number of entries in the cache
	Size int64

	// Evictions is the number of evicted entries
	Evictions int64

	// Backend is the name of the cache backend
	Backend string
}

CacheStats contains cache statistics.

func (*CacheStats) HitRatio

func (s *CacheStats) HitRatio() float64

HitRatio returns the cache hit ratio (0.0 to 1.0).

type NoOpCache

type NoOpCache struct{}

NoOpCache is a no-operation cache implementation. It satisfies the Cache interface but doesn't actually cache anything. This is the default implementation for backward compatibility.

func NewNoOpCache

func NewNoOpCache() *NoOpCache

NewNoOpCache creates a new no-op cache instance.

func (*NoOpCache) Clear

func (c *NoOpCache) Clear(ctx context.Context) error

Clear implements Cache.Clear (no-op).

func (*NoOpCache) Close

func (c *NoOpCache) Close() error

Close implements Cache.Close (no-op).

func (*NoOpCache) Delete

func (c *NoOpCache) Delete(ctx context.Context, key string) error

Delete implements Cache.Delete (no-op).

func (*NoOpCache) DeleteByTag

func (c *NoOpCache) DeleteByTag(ctx context.Context, tag string) error

DeleteByTag implements TaggedCache.DeleteByTag (no-op).

func (*NoOpCache) Exists

func (c *NoOpCache) Exists(ctx context.Context, key string) (bool, error)

Exists implements Cache.Exists (no-op).

func (*NoOpCache) Get

func (c *NoOpCache) Get(ctx context.Context, key string) (*CacheEntry, error)

Get implements Cache.Get (no-op).

func (*NoOpCache) GetStats

func (c *NoOpCache) GetStats(ctx context.Context) (*CacheStats, error)

GetStats implements StatsProvider.GetStats (no-op).

func (*NoOpCache) ListKeysByTag

func (c *NoOpCache) ListKeysByTag(ctx context.Context, tag string) ([]string, error)

ListKeysByTag implements TaggedCache.ListKeysByTag (no-op).

func (*NoOpCache) Name

func (c *NoOpCache) Name() string

Name implements Cache.Name.

func (*NoOpCache) Set

func (c *NoOpCache) Set(ctx context.Context, key string, value []byte, opts ...CacheOption) error

Set implements Cache.Set (no-op).

type StatsProvider

type StatsProvider interface {
	// GetStats returns cache statistics.
	GetStats(ctx context.Context) (*CacheStats, error)
}

StatsProvider provides cache statistics.

type TaggedCache

type TaggedCache interface {
	Cache

	// DeleteByTag removes all cache entries with the given tag.
	DeleteByTag(ctx context.Context, tag string) error

	// ListKeysByTag returns all keys with the given tag.
	ListKeysByTag(ctx context.Context, tag string) ([]string, error)
}

TaggedCache extends Cache with tag-based operations.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL