1
0

feat(cache): 实现 RoutingCache 和 StatsBuffer 优化数据库写入

- 新增 RoutingCache 组件,使用 sync.Map 缓存 Provider 和 Model
- 新增 StatsBuffer 组件,使用 sync.Map + atomic.Int64 缓冲统计数据
- 扩展 StatsRepository.BatchUpdate 支持批量增量更新
- 改造 RoutingService/StatsService/ProviderService/ModelService 集成缓存
- 更新 usage-statistics spec,新增 routing-cache 和 stats-buffer spec
- 新增单元测试覆盖缓存命中/失效/并发场景
This commit is contained in:
2026-04-22 19:24:36 +08:00
parent f5e45d032e
commit df253559a5
20 changed files with 1377 additions and 91 deletions

View File

@@ -11,27 +11,30 @@ import (
type modelService struct {
modelRepo repository.ModelRepository
providerRepo repository.ProviderRepository
cache *RoutingCache
}
func NewModelService(modelRepo repository.ModelRepository, providerRepo repository.ProviderRepository) ModelService {
return &modelService{modelRepo: modelRepo, providerRepo: providerRepo}
func NewModelService(modelRepo repository.ModelRepository, providerRepo repository.ProviderRepository, cache *RoutingCache) ModelService {
return &modelService{modelRepo: modelRepo, providerRepo: providerRepo, cache: cache}
}
func (s *modelService) Create(model *domain.Model) error {
// 校验供应商存在
if _, err := s.providerRepo.GetByID(model.ProviderID); err != nil {
return appErrors.ErrProviderNotFound
}
// 联合唯一校验:同一供应商下 model_name 不重复
if err := s.checkDuplicateModelName(model.ProviderID, model.ModelName, ""); err != nil {
return err
}
// 自动生成 UUID 作为 id
model.ID = uuid.New().String()
model.Enabled = true
return s.modelRepo.Create(model)
err := s.modelRepo.Create(model)
if err != nil {
return err
}
s.cache.SetModel(model)
return nil
}
func (s *modelService) Get(id string) (*domain.Model, error) {
@@ -47,20 +50,17 @@ func (s *modelService) ListEnabled() ([]domain.Model, error) {
}
func (s *modelService) Update(id string, updates map[string]interface{}) error {
// 获取当前模型
current, err := s.modelRepo.GetByID(id)
if err != nil {
return appErrors.ErrModelNotFound
}
// 如果更新 provider_id校验新供应商存在
if providerID, ok := updates["provider_id"].(string); ok {
if _, err := s.providerRepo.GetByID(providerID); err != nil {
return appErrors.ErrProviderNotFound
}
}
// 确定更新后的 provider_id 和 model_name
newProviderID := current.ProviderID
if v, ok := updates["provider_id"].(string); ok {
newProviderID = v
@@ -70,18 +70,37 @@ func (s *modelService) Update(id string, updates map[string]interface{}) error {
newModelName = v
}
// 如果 provider_id 或 model_name 发生变化,校验联合唯一
if newProviderID != current.ProviderID || newModelName != current.ModelName {
if err := s.checkDuplicateModelName(newProviderID, newModelName, id); err != nil {
return err
}
}
return s.modelRepo.Update(id, updates)
err = s.modelRepo.Update(id, updates)
if err != nil {
return err
}
s.cache.InvalidateModel(current.ProviderID, current.ModelName)
if newProviderID != current.ProviderID || newModelName != current.ModelName {
s.cache.InvalidateModel(newProviderID, newModelName)
}
return nil
}
func (s *modelService) Delete(id string) error {
return s.modelRepo.Delete(id)
model, err := s.modelRepo.GetByID(id)
if err != nil {
return appErrors.ErrModelNotFound
}
err = s.modelRepo.Delete(id)
if err != nil {
return err
}
s.cache.InvalidateModel(model.ProviderID, model.ModelName)
return nil
}
// checkDuplicateModelName 校验同一供应商下 model_name 是否重复