[ PROMPT_NODE_24092 ]
Durable Objects 常见陷阱
[ SKILL_DOCUMENTATION ]
# Durable Objects 注意事项
## 常见错误
### "休眠清除了我的内存状态"
**问题**:休眠后变量丢失
**原因**:DO 在空闲时自动休眠;内存状态未持久化
**解决方案**:对关键数据使用 `ctx.storage`,对每个连接的元数据使用 `ws.serializeAttachment()`
typescript
// ❌ 错误 - 休眠时丢失
private userCount = 0;
async webSocketMessage(ws: WebSocket, msg: string) {
this.userCount++; // 丢失!
}
// ✅ 正确 - 已持久化
async webSocketMessage(ws: WebSocket, msg: string) {
const count = this.ctx.storage.kv.get("userCount") || 0;
this.ctx.storage.kv.put("userCount", count + 1);
}
### "setTimeout 在重启后未触发"
**问题**:驱逐后计划任务丢失
**原因**:`setTimeout` 仅存在于内存中;驱逐会清除定时器
**解决方案**:使用 `ctx.storage.setAlarm()` 进行可靠调度
typescript
// ❌ 错误 - 驱逐时丢失
setTimeout(() => this.cleanup(), 3600000);
// ✅ 正确 - 在驱逐后依然有效
await this.ctx.storage.setAlarm(Date.now() + 3600000);
async alarm() { await this.cleanup(); }
### "构造函数在每次唤醒时运行"
**问题**:昂贵的初始化逻辑拖慢了所有请求
**原因**:构造函数在每次唤醒时运行(驱逐后的第一个请求 OR 休眠后的唤醒)
**解决方案**:懒加载或在存储中缓存
**关键理解**:构造函数在两种情况下运行:
1. **冷启动** - DO 从内存中被驱逐,第一个请求创建新实例
2. **从休眠中唤醒** - 带有 WebSocket 的 DO 进入休眠,消息/闹钟将其唤醒
typescript
// ❌ 错误 - 每次唤醒都很昂贵
constructor(ctx: DurableObjectState, env: Env) {
super(ctx, env);
this.heavyData = this.loadExpensiveData(); // 慢!
}
// ✅ 正确 - 懒加载
private heavyData?: HeavyData;
private getHeavyData() {
if (!this.heavyData) this.heavyData = this.loadExpensiveData();
return this.heavyData;
}
### "Durable Object 过载 (503 错误)"
**问题**:负载下出现 503 错误
**原因**:单个 DO 超过了约 1K req/s 的吞吐量限制
**解决方案**:跨多个 DO 分片(参见 [模式: 分片](./patterns.md))
### "存储配额超出 (写入失败)"
**问题**:写入操作失败
**原因**:DO 存储超过 10GB 限制或账户配额
**解决方案**:使用闹钟进行清理,对旧数据使用 `deleteAll()`,升级套餐
### "CPU 时间超出 (已终止)"
**问题**:请求在执行中途被终止
**原因**:处理