Add projects
This commit is contained in:
parent
2d3a9ad623
commit
8b607dd700
1802 changed files with 503346 additions and 2 deletions
128
backend/internal/runtime/executor/helps/cache_helpers.go
Normal file
128
backend/internal/runtime/executor/helps/cache_helpers.go
Normal file
|
|
@ -0,0 +1,128 @@
|
|||
package helps
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
homekv "github.com/router-for-me/CLIProxyAPI/v7/internal/home"
|
||||
)
|
||||
|
||||
type CodexCache struct {
|
||||
ID string
|
||||
Expire time.Time
|
||||
}
|
||||
|
||||
// codexCacheMap stores prompt cache IDs keyed by model+user_id.
|
||||
// Protected by codexCacheMu. Entries expire after 1 hour.
|
||||
var (
|
||||
codexCacheMap = make(map[string]CodexCache)
|
||||
codexCacheMu sync.RWMutex
|
||||
)
|
||||
|
||||
// codexCacheCleanupInterval controls how often expired entries are purged.
|
||||
const codexCacheCleanupInterval = 15 * time.Minute
|
||||
|
||||
// codexCacheCleanupOnce ensures the background cleanup goroutine starts only once.
|
||||
var codexCacheCleanupOnce sync.Once
|
||||
|
||||
// startCodexCacheCleanup launches a background goroutine that periodically
|
||||
// removes expired entries from codexCacheMap to prevent memory leaks.
|
||||
func startCodexCacheCleanup() {
|
||||
go func() {
|
||||
ticker := time.NewTicker(codexCacheCleanupInterval)
|
||||
defer ticker.Stop()
|
||||
for range ticker.C {
|
||||
purgeExpiredCodexCache()
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
// purgeExpiredCodexCache removes entries that have expired.
|
||||
func purgeExpiredCodexCache() {
|
||||
now := time.Now()
|
||||
codexCacheMu.Lock()
|
||||
defer codexCacheMu.Unlock()
|
||||
for key, cache := range codexCacheMap {
|
||||
if cache.Expire.Before(now) {
|
||||
delete(codexCacheMap, key)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// GetCodexCache retrieves a cached entry, returning ok=false if not found or expired.
|
||||
func GetCodexCache(key string) (CodexCache, bool) {
|
||||
cache, ok, err := GetCodexCacheRequired(context.Background(), key)
|
||||
if err == nil {
|
||||
return cache, ok
|
||||
}
|
||||
return CodexCache{}, false
|
||||
}
|
||||
|
||||
// GetCodexCacheRequired retrieves a cached entry for request-time paths.
|
||||
func GetCodexCacheRequired(ctx context.Context, key string) (CodexCache, bool, error) {
|
||||
var homeCache CodexCache
|
||||
homeMode, found, errGet := homekv.KVGetJSONRequired(ctx, key, &homeCache)
|
||||
if homeMode {
|
||||
if errGet != nil || !found {
|
||||
return CodexCache{}, false, errGet
|
||||
}
|
||||
if homeCache.Expire.Before(time.Now()) {
|
||||
_, _, _ = homekv.KVDelRequired(ctx, key)
|
||||
return CodexCache{}, false, nil
|
||||
}
|
||||
return homeCache, true, nil
|
||||
}
|
||||
|
||||
codexCacheCleanupOnce.Do(startCodexCacheCleanup)
|
||||
codexCacheMu.RLock()
|
||||
cache, ok := codexCacheMap[key]
|
||||
codexCacheMu.RUnlock()
|
||||
if !ok || cache.Expire.Before(time.Now()) {
|
||||
return CodexCache{}, false, nil
|
||||
}
|
||||
return cache, true, nil
|
||||
}
|
||||
|
||||
// SetCodexCache stores a cache entry.
|
||||
func SetCodexCache(key string, cache CodexCache) {
|
||||
SetCodexCacheBestEffort(context.Background(), key, cache)
|
||||
}
|
||||
|
||||
// SetCodexCacheRequired stores a cache entry for request-time paths.
|
||||
func SetCodexCacheRequired(ctx context.Context, key string, cache CodexCache) error {
|
||||
ttl := time.Until(cache.Expire)
|
||||
if ttl <= 0 {
|
||||
return nil
|
||||
}
|
||||
if _, homeMode, _ := homekv.CurrentKVClient(); homeMode {
|
||||
_, errSet := homekv.KVSetJSONRequired(ctx, key, cache, ttl)
|
||||
return errSet
|
||||
}
|
||||
codexCacheCleanupOnce.Do(startCodexCacheCleanup)
|
||||
codexCacheMu.Lock()
|
||||
codexCacheMap[key] = cache
|
||||
codexCacheMu.Unlock()
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetCodexCacheBestEffort stores a cache entry without failing completed responses.
|
||||
func SetCodexCacheBestEffort(ctx context.Context, key string, cache CodexCache) bool {
|
||||
ttl := time.Until(cache.Expire)
|
||||
if ttl <= 0 {
|
||||
return false
|
||||
}
|
||||
if _, homeMode, _ := homekv.CurrentKVClient(); homeMode {
|
||||
return homekv.KVSetJSONBestEffort(ctx, key, cache, ttl)
|
||||
}
|
||||
codexCacheCleanupOnce.Do(startCodexCacheCleanup)
|
||||
codexCacheMu.Lock()
|
||||
codexCacheMap[key] = cache
|
||||
codexCacheMu.Unlock()
|
||||
return true
|
||||
}
|
||||
|
||||
// CodexPromptCacheKey builds the Home KV key for a model/user prompt cache.
|
||||
func CodexPromptCacheKey(modelName string, userScope string) string {
|
||||
return "cpa:codex:prompt-cache:" + homekv.HashKeyPart(modelName) + ":" + homekv.HashKeyPart(userScope)
|
||||
}
|
||||
Loading…
Reference in a new issue