CoCache
wow-cocache 连接 Wow 查询/事件合同与 CoCache Cache SPI。需要按聚合 ID 缓存读模型,并希望在领域事件到达时逐出或按状态事件主动更新时使用;它不自动创建 cache backend,也不自动注册任何业务缓存。
特性
QueryGatewayCacheSource从本地SnapshotQueryGateway加载;QueryApiCacheSource从远程ReactiveSnapshotQueryApi加载,并把 404 转为空;EvictStateCacheRefresher消费领域事件并逐出;SetStateCacheRefresher消费状态事件并 set,deleted state 改为逐出。
应用拥有 cache key、数据转换、TTL、backend、容量、一致性目标和 Bean 注册;CoCache backend 拥有 eviction/TTL/存储语义。
安装
implementation("me.ahoo.wow:wow-cocache")Starter 没有 cocache-support capability,也没有 wow.cocache.* 自动配置。最小可用条件是:一个现有 Cache<K,D>、一个 source(需要 miss load 时)以及一个显式注册的 refresher(需要事件刷新时)。
快速开始
先确定聚合、key 类型、缓存 DTO 和刷新策略,再只注册所需组件。
1. 配置 CoCache 缓存
使用应用现有 CoCache 配置创建 Cache<String, OrderView>。wow-cocache 不选择 Redis、本地 map 或其他 backend,也不复制 backend 的连接/序列化校验。
2. 注册缓存源(缓存未命中时加载)
@Bean
fun orderCacheSource(queryGateway: SnapshotQueryGateway<OrderState>) =
QueryGatewayCacheSource(
snapshotQueryGateway = queryGateway,
stateToCacheDataConverter = { snapshot -> OrderView(snapshot.state) },
)默认 LoadCacheSourceConfiguration 为 timeout=10s 和 CoCache 默认 TTL/amplitude。loadCacheValue 是 CoCache 同步 SPI:它等待 Reactor source,超时或查询异常会传播;不要从 Reactor event loop 直接调用阻塞 miss loader。
3. 注册缓存刷新器(事件驱动刷新)
@Bean
fun orderCacheRefresher(
cache: Cache<String, OrderView>,
) = EvictStateCacheRefresher<String, OrderState, OrderView>(
namedAggregate = ORDER,
cache = cache,
)Refresher 是 MessageFunction,必须进入应用的事件处理器发现/注册流程;构造对象本身不会订阅总线。
缓存刷新策略
逐出更简单,下一次读取重新加载;主动 set 减少 miss,但依赖状态事件总线、converter 和 TTL 正确。两者都只提供最终一致的缓存刷新,不是与 EventStore 同一事务。
逐出策略(Evict)
EvictStateCacheRefresher 的 functionKind=EVENT,默认把 aggregateId.id 转为 key 并调用 cache.evict。key 类型不是 String 时提供 keyConvert,不要依赖 unchecked cast。
更新策略(Set)
SetStateCacheRefresher 的 functionKind=STATE_EVENT。非 deleted 状态经 StateToCacheDataConverter 写成 DefaultCacheValue.ttlAt,deleted 状态逐出。TTL 默认来自 CoCache,也可在构造时覆盖。
缓存加载源
source 只负责 miss load 与 DTO 转换。权限、tenant/space 作用域和不存在语义必须由所调用 Gateway/API 的公共合同保证。
QueryGatewayCacheSource
它构造按 aggregateId 的 single query。空结果返回 null cache value;查询错误和 timeout 不会伪装成 cache miss。
QueryApiCacheSource
它同时实现 ReactiveSnapshotQueryApi 与 StateCacheSource,getById 的 not-found 转为空,其他 HTTP/解码失败继续传播。不要把远端不可用缓存为“不存在”。
已验证失败/边界:空 source 不写缓存;deleted state 逐出;miss loader timeout/异常传播;cache 操作异常使 refresher 失败并由事件处理恢复策略处理。
聚焦检查:
./gradlew :wow-cocache:check