feat: 使用 ttlcache 优化指纹缓存管理

- 添加指纹缓存迁移决策,选用零依赖的 ttlcache 库并配置单例缓存与十分钟过期时间。
- 使用 `@isaacs/ttlcache` 成功替换手动 TTL 缓存并保留请求去重逻辑,优化依赖管理与代码格式化流程。
- 添加缓存库选型说明,明确采用 @isaacs/ttlcache 提升硬件指纹功能的可维护性与稳定性。
- 添加 ttlcache 依赖以支持缓存功能
- 使用 TTLCache 替代手动缓存逻辑,提升缓存管理的可靠性和可维护性。
- 添加 @isaacs/ttlcache 依赖并指定版本 2.1.4,更新锁定文件以确保依赖一致性。
- 添加 ttlcache 依赖以支持缓存功能
This commit is contained in:
2026-01-26 11:27:10 +08:00
parent 42bd3a7657
commit 158e7291d1
7 changed files with 63 additions and 8 deletions

View File

@@ -346,6 +346,37 @@ const fingerprint = createHash('sha256')
- 深入研究文档和源码再做技术决策
- 区分"用户输入场景"和"系统数据场景"的安全要求
### 缓存库选择:@isaacs/ttlcache
**决策时间**: 2026-01-26
**背景**
硬件指纹功能最初使用手动实现的 TTL 缓存module-level 变量 + 手动过期检查)。为提高代码可维护性,迁移到专业缓存库。
**选型**
- **选择**: `@isaacs/ttlcache` v2.1.4
- **理由**:
- 专为 TTL 场景优化,无需 LRU 追踪开销
- 零依赖6M+ 周下载量
- 内置 TypeScript 类型
- 自动过期管理,无需手动定时器
- API 简洁: `new TTLCache({ ttl, max })`
**实现细节**
- 保留 `inFlight` Promise 模式用于并发请求去重TTLCache 不提供此功能)
- 使用单一缓存键 `'fingerprint'`单服务器场景opts 不影响输出)
- 默认 TTL: 10 分钟(可通过 `cacheTtlMs` 参数覆盖)
**对比手动实现**
- ✅ 更少自定义代码
- ✅ 更清晰的 TTL 语义
- ✅ 经过充分测试的库
- ⚠️ 仍需手动处理并发去重
**经验教训**
- 专业库不一定解决所有问题(如并发去重)
- 对于简单场景,手动实现 vs 库的选择主要取决于可维护性而非功能
### Git 工作流要求
**重要原则**:保持代码仓库与文档同步

View File

@@ -15,6 +15,7 @@
"typecheck": "tsc --noEmit"
},
"dependencies": {
"@isaacs/ttlcache": "catalog:",
"@orpc/client": "catalog:",
"@orpc/contract": "catalog:",
"@orpc/openapi": "catalog:",

View File

@@ -1,3 +1,4 @@
import { TTLCache } from '@isaacs/ttlcache'
import { hash } from 'ohash'
import si from 'systeminformation'
@@ -63,10 +64,10 @@ export type HardwareFingerprintResult = {
}
// 缓存实例
let cache: {
expiresAt: number
value: HardwareFingerprintResult
} | null = null
const cache = new TTLCache<'fingerprint', HardwareFingerprintResult>({
ttl: 10 * 60 * 1000, // 10 minutes default
max: 1, // Only one fingerprint cached
})
// 防止并发重复请求
let inFlight: Promise<HardwareFingerprintResult> | null = null
@@ -182,8 +183,9 @@ export async function getHardwareFingerprint(
const now = Date.now()
// 返回缓存结果
if (cache && cache.expiresAt > now) {
return cache.value
const cached = cache.get('fingerprint')
if (cached) {
return cached
}
// 防止并发重复请求
@@ -212,7 +214,7 @@ export async function getHardwareFingerprint(
}
// 更新缓存
cache = { expiresAt: now + ttl, value: result }
cache.set('fingerprint', result, { ttl })
return result
})().finally(() => {
@@ -226,6 +228,6 @@ export async function getHardwareFingerprint(
* 清除指纹缓存(用于测试或强制刷新)
*/
export function clearFingerprintCache(): void {
cache = null
cache.clear()
inFlight = null
}