[ PROMPT_NODE_24080 ]
Do Storage 常见陷阱
[ SKILL_DOCUMENTATION ]
# DO 存储陷阱与故障排除
## 并发模型 (关键)
Durable Objects 使用 **输入/输出门控** 来防止竞态条件:
### 输入门控
在当前请求进行存储读取时阻塞新请求:
typescript
// 安全: await 期间输入门控处于激活状态
async increment() {
const val = await this.ctx.storage.get("counter"); // 输入门控阻塞其他请求
await this.ctx.storage.put("counter", val + 1);
return val;
}
### 输出门控
在当前请求的所有写入确认前保持响应:
typescript
// 安全: 输出门控等待 put() 确认后再返回响应
async increment() {
const val = await this.ctx.storage.get("counter");
this.ctx.storage.put("counter", val + 1); // 无 await
return new Response(String(val)); // 响应延迟至写入确认
}
### 写入合并
对同一键的多次写入 = 原子操作 (最后一次写入生效):
typescript
// 安全: 所有三次写入原子性合并
this.ctx.storage.put("key", 1);
this.ctx.storage.put("key", 2);
this.ctx.storage.put("key", 3); // 最终值: 3
### 打破门控 (危险)
**fetch() 会打破输入/输出门控** → 允许请求交错:
typescript
// 不安全: fetch() 允许另一个请求交错执行
async unsafe() {
const val = await this.ctx.storage.get("counter");
await fetch("https://api.example.com"); // 门控被打破!
await this.ctx.storage.put("counter", val + 1); // 可能产生竞态条件
}
**解决方案:** 使用 `blockConcurrencyWhile()` 或 `transaction()`:
typescript
// 安全: 显式阻塞并发请求
async safe() {
return await this.ctx.blockConcurrencyWhile(async () => {
const val = await this.ctx.storage.get("counter");
await fetch("https://api.example.com");
await this.ctx.storage.put("counter", val + 1);
return val;
});
}
### allowConcurrency 选项
对于不需要保护的读取,可选择退出输入门控:
typescript
// 允许并发读取 (无一致性保证)
const val = await this.ctx.storage.get("metrics", { allowConcurrency: true });
## 常见错误
### "Race Condition in Concurrent Calls" (并发调用中的竞态条件)
**原因:** 同一事件中发起的多个并发存储操作(例如 `Promise.all()`)不受输入门控保护
**解决方案:** 避免在单个事件内进行并发存储操作;输入门控仅序列化来自不同事件的请求,而非同一事件内的操作
### "Direct SQL Transaction Statements" (直接 SQL 事务语句)
**Ca