使用已连接MongoDB实例初始化Agenda后定时任务不执行如何解决
问题根因
- 事件监听时序错误
你在调用agendaTmp.mongo(database, "newNotification")时,传入的database已经是已连接状态,Agenda会立刻触发ready事件,但你是在Promise resolve之后、拿到agenda实例时才绑定ready事件监听,此时事件已经触发完成,回调内的await agendaTmp.agenda.start()根本没有执行,Agenda没有启动任务消费进程,所以只会写入任务不会执行。 - 异步初始化未等待
agenda.mongo()方法本身是异步方法,你没有等待该方法执行完成就直接resolve返回agenda实例,会导致实例状态不稳定,偶现任务写入/执行异常。 - 外部MongoClient缺省配置
你自行初始化的MongoClient没有配置Agenda所需的长连接保活、连接池参数,高内存占用下JavaScript主进程事件循环调度延迟,MongoDB连接心跳检测失败触发断连,就会抛出MongoNetworkError。Agenda自行创建连接时会默认配置适配定时任务场景的连接参数,所以不会出现该问题。
修复方案
1. 修改Agenda初始化逻辑
等待mongo()方法初始化完成再返回实例,同时给MongoClient增加保活配置:
// Agenda init file import { Agenda } from "agenda"; import { MongoClient } from "mongodb"; const agenda = new Promise(async (resolve, reject) => { // 给MongoClient增加长连接保活、连接池配置 const client = new MongoClient(dbURL, { maxPoolSize: 10, minPoolSize: 2, heartbeatFrequencyMS: 10000, connectTimeoutMS: 30000, socketTimeoutMS: 0, // 长连接不超时 }); try { await client.connect(); const database = client.db("scheduler"); // 测试查询可保留也可删除 const result = await database.collection("newNotification").findOne({}); console.log("In mongo query: ", result); const agendaTmp = new Agenda({ processEvery: "40 seconds", }); // 等待mongo方法初始化完成 await agendaTmp.mongo(database, "newNotification"); resolve({ agenda: agendaTmp, status: true }); } catch (err) { reject(false); } }); export { agenda };
2. 修改调用逻辑
删除无效的ready事件监听,直接定义任务、启动Agenda后再创建定时规则:
agenda.then(async (agendaTmp: any) => { console.log("Received: ", agendaTmp.status); const agendaInstance = agendaTmp.agenda; // 先定义任务 agendaInstance.define("test3", {}, (job: any, done: any) => { console.log("New agendaTmp schedule running"); done(); }); // 直接启动agenda,不需要等ready事件 await agendaInstance.start(); console.log("Agenda started"); // 启动完成后再创建定时任务 agendaInstance.every("*/1 * * * *", "test3", {}); })
验证逻辑
修改后启动服务,可观察到两个现象:
- 每分钟会打印
New agendaTmp schedule running日志 - 高内存场景下不会再出现MongoDB断连错误
内容的提问来源于stack exchange,提问作者Dhavan Kantharaj
相关产品推荐
相关产品推荐

