DocumentDB 4.0中TTL索引expireAfterSeconds设置失效问题求助
解决DocumentDB 4.0中Mongoose TTL不生效的问题
可能的原因及解决步骤
1. 确保TTL索引已正确创建
Mongoose定义索引后未必会立即在DocumentDB集合上生效,尤其是集合已存在的情况。可以直接在DocumentDB控制台或Mongo Shell执行以下命令,确认索引是否存在:
db.locks.getIndexes()
返回结果中需包含类似如下的TTL索引:
{ "v": 2, "key": { "createdAt": 1 }, "name": "createdAt_1", "expireAfterSeconds": 30 }
如果索引缺失,在代码中手动触发索引创建:
const Lock = mongoose.model("migration", LockSchema, "locks"); // 确保所有索引(包括TTL)创建完成 await Lock.createIndexes();
2. 严格保证createdAt为Date类型
DocumentDB的TTL机制仅对Date类型字段生效,字符串(包括ISO格式字符串)不会触发自动过期。Mongoose中需确保字段定义和插入值均为Date类型:
- 字段定义时,显式使用
type: Date,并推荐用函数返回Date对象作为默认值(避免时间戳被误处理):
createdAt: { type: Date, required: true, default: () => new Date() },
- 插入/更新文档时,不要将
createdAt设置为字符串,确保传入的是Date对象。
3. 注意TTL清理的延迟特性
DocumentDB的TTL后台清理任务并非实时执行,默认执行间隔约为60秒。也就是说,文档过期后,可能需要等待30秒(过期时间)+ 60秒(清理间隔)左右才会被删除,不要期望到点立即消失。
4. 确认集合名称匹配
代码中创建模型时指定了集合名为locks:
const Lock = mongoose.model("migration", LockSchema, "locks");
需确保后续操作的是locks集合,而非Mongoose自动生成的复数集合名(比如migrations)。
修改后的示例代码
const mongoose = require('mongoose'); const { Schema } = require("mongoose"); const { v4: uuidv4 } = require('uuid'); const util = require('util'); const exec = util.promisify(require("child_process").exec); const whoAmI = uuidv4(); (async () => { await mongoose.connect(connectionString); const LockSchema = new Schema({ id: String, owner: String, createdAt: { type: Date, required: true, default: () => new Date() }, }); LockSchema.index({ "createdAt": 1 }, { expireAfterSeconds: 30 }); const Lock = mongoose.model("migration", LockSchema, "locks"); // 确保TTL索引创建完成 await Lock.createIndexes(); const result = await Lock.findOneAndUpdate( { id: "lock" }, { $setOnInsert: { owner: whoAmI }}, { upsert: true, new: true } ).lean(); if (result?.owner === whoAmI) { try { const { stdout, stderr } = await exec("<something>"); if (stderr) { console.log(`stderr: ${stderr}`); } console.log("done..."); } catch (error) { console.log(`error: ${error.message}`); } finally { await mongoose.disconnect(); } } else { await mongoose.disconnect(); } })();
注:代码中把exec包装成了Promise,避免异步回调导致的连接提前断开问题,同时确保无论执行成功或失败都会正确断开连接。
内容的提问来源于stack exchange,提问作者aggaton
相关产品推荐
相关产品推荐

