Mini Session Storage¶
从 5105 行的
src/utils/sessionStorage.ts提炼到 ~150 行 的 file-based KV + TTL + 原子写 + 事务。 8 个测试场景:基本 / 持久化 / reload / TTL / 事务 / delete / 并发安全 / debounced flush。
文件¶
mini-session-storage/
├── src/
│ ├── storage.ts SessionStorage 类(~150 行)
│ └── cli.ts 8 测试场景
└── README.md
跑¶
真实代码对照¶
| Demo | 真实文件 | 简化 |
|---|---|---|
set/get |
sessionStorage.ts:200 |
直接 Map |
load 启动恢复 |
sessionStorage.ts:500 (~300 行) |
单文件 JSON |
| 原子写 | sessionStorage.ts:800 (~200 行) |
write tmp + rename |
transaction |
sessionStorage.ts:1500 (~400 行) |
内存批量 + 单次 flush |
| TTL 懒清理 | sessionStorage.ts:2500 |
get 时检查 |
| Crash recovery | sessionStorage.ts:4000 |
简化为 tmp + rename |
核心 4 件套¶
1️⃣ 内存 Map + 磁盘 JSON¶
- 写:先改内存(同步),调度后台 flush(debounce 1s)
- 读:只查内存(不 IO,O(1))
- 启动:load 整个 JSON
2️⃣ 原子写 = write tmp + fsync + rename¶
const tmpPath = `${filePath}.${pid}.${rand}.tmp`;
await fs.writeFile(tmpPath, JSON.stringify(data));
await fd.sync(); // 强制刷盘(防断电)
await fs.rename(tmpPath, filePath); // 原子替换
3️⃣ Debounced flush¶
private scheduleFlush() {
if (this.flushTimer) return;
this.flushTimer = setTimeout(() => this.flush(), 1000);
}
4️⃣ TTL 懒清理¶
if (entry.expiresAt && Date.now() > entry.expiresAt) {
delete this.data.entries[key];
return null;
}
8 个场景输出¶
📌 Test 1: set / get
📌 Test 2: persistence (close → file)
file exists: size=423 bytes
📌 Test 3: reload
user.name (reloaded) = Alice
📌 Test 4: TTL expiration
expired? ✅
📌 Test 5: transaction (batch)
todo.1 = buy milk, todo.2 = learn CC, todo.3 = build demo
📌 Test 6: delete
delete returned: true
📌 Test 7: concurrent flush safety
✅ file is valid JSON (atomic rename worked)
📌 Test 8: graceful close
file size=171, final.value in file? true
进阶练习¶
- 换 SQLite:用 better-sqlite3 替代 JSON(更大数据 + 索引)
- 加 fsync on every write:金融场景每次写都 fsync(牺牲性能换安全)
- 加 WAL 模式:写前 log 防 crash 丢数据
- 加 compression:用 lz4 压缩大 value
- 加 change notification:写后触发订阅者(pub/sub)
- 加 watch:文件外部修改时自动 reload(inotify)
相关阅读¶
- topics/deep-dive-session-storage.md —— 5105 行完整分析
- phase-06-agent-loop.md —— session 用在哪
- docs/SECURITY_MODEL.md —— session 安全模型
- POSIX rename 原子性
- Node fs.promises API