Files
OpenFlare/.agents/skills/cache-framework/SKILL.md
T

108 lines
3.8 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.
---
name: "cache-framework"
description: "Wavelet 项目专用:当新增或修改基于 Cordis 插件的业务缓存、ctx.Cache() / contracts.CacheService 访问、三层读路径(RAM L1 + Redis L2 + DB L3)、多节点 Pub/Sub 失效同步时必须使用。"
---
# 系统三层缓存框架与开发规范 (Cordis 插件化架构)
本技能指导 Wavelet 在 Cordis 架构下,如何使用平台统一提供的三层缓存服务(`ctx.Cache()` 与 `contracts.CacheService`)进行高性能缓存读写与分布式失效同步。
---
## 1. 三层读路径与标准契约
Wavelet 标准读路径为 **本地 RAM (L1) → Redis (L2) → Database (L3)**(由快到慢):
| 层级 | 技术 | 职责 |
| :--- | :--- | :--- |
| **L1 本地** | `pkg/cache/ram` (Otter) | 进程内纳秒级极速读取,抗最高频热点流量 |
| **L2 共享** | Redis 序列化缓存 | 跨节点共享,具备 TTL 与防击穿保护 |
| **L3 权威** | 关系型数据库 (PostgreSQL / SQLite) | 唯一权威数据源 |
### 标准接口契约 (`contracts.CacheService`)
```go
type CacheService interface {
// Get 从缓存获取并反序列化至 target,若不存在返回 ErrCacheMiss
Get(ctx context.Context, key string, target any) error
// Set 存储对象至缓存并设置 TTL
Set(ctx context.Context, key string, value any, ttl time.Duration) error
// Delete 彻底移除缓存(清空本地 RAM、删除 Redis 并广播 Pub/Sub 通知全集群清空 RAM)
Delete(ctx context.Context, key string) error
// GetOrSet 优先读缓存,若未命中则执行 loader 回源加载并自动回写
GetOrSet(ctx context.Context, key string, target any, ttl time.Duration, loader func() (any, error)) error
// Invalidate 是 Delete 的语义别名
Invalidate(ctx context.Context, key string) error
}
```
---
## 2. 业务使用标准范式
### 2.1 高性能读穿透 (`GetOrSet`)
业务 Service 推荐优先使用 `GetOrSet`,框架底层自动完成 L1/L2 穿透、回写及并发防击穿:
```go
func (s *OrderService) GetOrderWithCache(ctx context.Context, orderID string) (*Order, error) {
var order Order
cacheKey := "order:" + orderID
err := s.cache.GetOrSet(ctx, cacheKey, &order, 10*time.Minute, func() (any, error) {
// Cache Miss: 执行 DB 回源查询
var dbOrder Order
if err := s.db.WithContext(ctx).First(&dbOrder, "id = ?", orderID).Error; err != nil {
return nil, err
}
return &dbOrder, nil
})
if err != nil {
return nil, err
}
return &order, nil
}
```
### 2.2 数据变更与失效广播 (`Invalidate` / `Delete`)
凡涉及数据创建、修改、软删除、状态变更的入口(**包含 HTTP Handler、后台 Worker 任务、定时清理任务**),必须调用缓存失效:
```go
func (s *OrderService) UpdateOrderStatus(ctx context.Context, orderID string, newStatus string) error {
// 1. 更新数据库权威数据
if err := s.db.WithContext(ctx).Model(&Order{}).Where("id = ?", orderID).Update("status", newStatus).Error; err != nil {
return err
}
// 2. 广播失效缓存(自动清除本机 L1、删除 Redis L2,并向集群广播 Pub/Sub 消息清空其他节点 L1)
return s.cache.Invalidate(ctx, "order:"+orderID)
}
```
---
## 3. 核心规则与禁止写法 (Guardrails)
1. **严禁自研本地 map 缓存**:
- 严禁在插件内编写 `sync.RWMutex + map[string]Xxx` 的裸内存缓存,无法感知多节点数据变更,必然引发多机脏读。
2. **写路径必须全覆盖失效**:
- 不仅在 API 修改时失效,后台 Worker、定时任务执行数据清理或变更时,必须同步触发 `cache.Invalidate`。
3. **Key 命名空间规范**:
- 缓存 Key 必须带插件命名空间前缀(如 `order:meta:{id}`、`auth:session:{token}`)。
4. **不可在业务高频读接口中绕过缓存直查 DB**。
---
## 4. 质量与测试验证
```bash
make format
make code-check
go test ./plugins/...
```