1
0
Files
nex/openspec/specs/routing-cache/spec.md
lanyuanxiaoyao df253559a5 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
- 新增单元测试覆盖缓存命中/失效/并发场景
2026-04-22 19:24:36 +08:00

137 lines
4.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Routing Cache
## Purpose
TBD - 为 Provider 和 Model 提供内存缓存,优化路由查询性能。
## Requirements
### Requirement: RoutingCache 缓存 Provider 和 Model
系统 SHALL 为 Provider 和 Model 提供内存缓存,使用 sync.Map 作为缓存数据结构。
#### Scenario: 缓存数据结构
- **WHEN** 创建 RoutingCache
- **THEN** SHALL 使用 sync.Map 存储 Providerkey = providerID
- **THEN** SHALL 使用 sync.Map 存储 Modelkey = providerID/modelName
### Requirement: 缓存查询优先
RoutingCache SHALL 优先从缓存查询,缓存未命中时查询数据库并更新缓存。
#### Scenario: 缓存命中
- **WHEN** 查询 Provider 或 Model
- **THEN** SHALL 先从缓存查询
- **THEN** 如果缓存命中SHALL 直接返回缓存值
- **THEN** SHALL 不查询数据库
#### Scenario: 缓存未命中
- **WHEN** 查询 Provider 或 Model
- **THEN** SHALL 先从缓存查询
- **THEN** 如果缓存未命中SHALL 查询数据库
- **THEN** SHALL 将查询结果存入缓存
- **THEN** SHALL 返回查询结果
#### Scenario: 双重检查防止竞态
- **WHEN** 并发查询同一个 Provider 或 Model
- **THEN** SHALL 在查询数据库后再次检查缓存
- **THEN** 如果已有其他 goroutine 存入缓存SHALL 使用缓存值
- **THEN** SHALL 防止存入旧值
### Requirement: 缓存更新
RoutingCache SHALL 支持 Create 操作后更新缓存。
#### Scenario: Create Provider 后更新缓存
- **WHEN** 创建 Provider 成功
- **THEN** SHALL 调用 RoutingCache.SetProvider
- **THEN** SHALL 将新 Provider 存入缓存
#### Scenario: Create Model 后更新缓存
- **WHEN** 创建 Model 成功
- **THEN** SHALL 调用 RoutingCache.SetModel
- **THEN** SHALL 将新 Model 存入缓存
### Requirement: 缓存失效
RoutingCache SHALL 支持 Update/Delete 操作后清除缓存。
#### Scenario: Update Provider 后清除缓存
- **WHEN** 更新 Provider 成功
- **THEN** SHALL 调用 RoutingCache.InvalidateProvider
- **THEN** SHALL 清除该 Provider 的缓存
- **THEN** SHALL 级联清除该 Provider 的所有 Model 缓存
#### Scenario: Delete Provider 后清除缓存
- **WHEN** 删除 Provider 成功
- **THEN** SHALL 调用 RoutingCache.InvalidateProvider
- **THEN** SHALL 清除该 Provider 的缓存
- **THEN** SHALL 级联清除该 Provider 的所有 Model 缓存
#### Scenario: Update Model 后清除缓存
- **WHEN** 更新 Model 成功
- **THEN** SHALL 调用 RoutingCache.InvalidateModel
- **THEN** SHALL 清除旧位置的 Model 缓存
- **THEN** 如果 provider_id 或 model_name 变化SHALL 也清除新位置的缓存
#### Scenario: Delete Model 后清除缓存
- **WHEN** 删除 Model 成功
- **THEN** SHALL 调用 RoutingCache.InvalidateModel
- **THEN** SHALL 清除该 Model 的缓存
### Requirement: 缓存预热
RoutingCache SHALL 支持启动时预热缓存。
#### Scenario: 预热成功
- **WHEN** 服务启动时
- **THEN** SHALL 调用 RoutingCache.Preload
- **THEN** SHALL 从数据库加载所有 Provider 到缓存
- **THEN** SHALL 从数据库加载所有 Model 到缓存
- **THEN** SHALL 记录预热完成的日志
#### Scenario: 预热失败
- **WHEN** 预热失败时
- **THEN** SHALL 记录警告日志
- **THEN** SHALL 继续启动服务
- **THEN** SHALL 使用懒加载(首次查询时加载)
### Requirement: RoutingService 使用缓存
RoutingService SHALL 使用 RoutingCache 进行路由查询。
#### Scenario: RouteByModelName 使用缓存
- **WHEN** 调用 RoutingService.RouteByModelName
- **THEN** SHALL 调用 RoutingCache.GetModel 获取 Model
- **THEN** SHALL 调用 RoutingCache.GetProvider 获取 Provider
- **THEN** SHALL 不直接调用 Repository
### Requirement: 并发安全
RoutingCache SHALL 支持并发访问。
#### Scenario: 并发查询
- **WHEN** 多个 goroutine 并发查询缓存
- **THEN** SHALL 无竞态条件
- **THEN** SHALL 无 panic
#### Scenario: 并发查询和失效
- **WHEN** 并发查询和失效缓存
- **THEN** SHALL 无竞态条件
- **THEN** SHALL 保证一致性