如何用Async Await实现Node.js脚本每6小时自动运行
Instagram生日倒计时自动更新简介解决方案
问题概述
现有基于instagram-private-api的Node.js异步脚本,功能为计算生日倒计时并更新Instagram个人简介,需要实现每6小时自动运行。尝试node-cron时出现未捕获Promise异常,同时拥有Heroku账号,寻求可行部署方案。
原脚本代码:
const { IgApiClient } = require("instagram-private-api") const ig = new IgApiClient() const USERNAME = "abc" const PASSWORD = "xyz" ig.state.generateDevice(USERNAME) const main = async () => { var birthday = new Date(2069, 05, 14); var today = new Date(); birthday.setFullYear(today.getFullYear()); if (today > birthday) { birthday.setFullYear(today.getFullYear() + 1); } var daystill = Math.floor((birthday - today) / (1000*60*60*24)) await ig.simulate.preLoginFlow() await ig.account.login(USERNAME, PASSWORD) process.nextTick(async () => await ig.simulate.postLoginFlow()) await ig.account.setBiography(`${daystill} Days till my Birthday, Today is ${new Date().getDate()}/${new Date().getMonth()}/${new Date().getFullYear()}. (AutoGenerated)`) } main()
使用node-cron时的报错:
node:internal/process/promises:288 triggerUncaughtException(err, true /* fromPromise */);
测试用node-cron代码:
cron.schedule('* * * * *', () => { // this is not every 6hrs const main = async () => { //same as above } main() })
报错原因
异步函数main()执行时未捕获Promise异常,且node-cron的回调中直接调用main()未处理错误,导致未捕获的Promise拒绝触发系统报错。
修复后的代码
带node-cron的稳定版本
const { IgApiClient } = require("instagram-private-api"); const cron = require("node-cron"); const ig = new IgApiClient(); // 建议通过环境变量存储账号密码,避免硬编码泄露 const USERNAME = process.env.IG_USERNAME || "abc"; const PASSWORD = process.env.IG_PASSWORD || "xyz"; ig.state.generateDevice(USERNAME); const main = async () => { try { // 计算生日倒计时(注意:JavaScript月份为0索引,5代表6月,需根据实际生日调整) const birthday = new Date(2069, 4, 14); const today = new Date(); birthday.setFullYear(today.getFullYear()); if (today > birthday) { birthday.setFullYear(today.getFullYear() + 1); } const daystill = Math.floor((birthday - today) / (1000 * 60 * 60 * 24)); // 执行IG登录与简介更新 await ig.simulate.preLoginFlow(); await ig.account.login(USERNAME, PASSWORD); process.nextTick(async () => await ig.simulate.postLoginFlow()); await ig.account.setBiography( `${daystill} Days till my Birthday, Today is ${today.getDate()}/${today.getMonth() + 1}/${today.getFullYear()}. (AutoGenerated)` ); console.log("简介更新完成"); } catch (error) { console.error("任务执行失败:", error); } }; // 配置每6小时执行一次的定时规则(分钟 小时 日 月 周) cron.schedule("0 */6 * * *", () => { console.log("启动定时任务..."); main(); }); // 脚本启动时立即执行一次 main();
关键修复点
- 给
main()添加try/catch捕获所有异步错误,避免未捕获Promise异常 - 修正日期月份索引问题:JavaScript的
Date对象月份从0开始,原代码的05实际对应6月,需根据实际生日调整 - 改用环境变量存储账号密码,提升安全性,适配Heroku部署
- 配置正确的cron表达式
0 */6 * * *,实现每6小时整点执行
Heroku部署方案
方案1:基于node-cron保持Dyno运行
- 在项目根目录创建
Procfile,内容为:worker: node your-script-filename.js - 将代码推送到Heroku仓库后,启动worker dyno:
heroku ps:scale worker=1 - 设置环境变量存储IG账号密码:
heroku config:set IG_USERNAME=你的Instagram账号 IG_PASSWORD=你的Instagram密码 - 注意:Heroku免费Dyno每日会休眠6小时,可能导致定时任务遗漏,若需稳定运行可考虑升级付费Dyno。
方案2:使用Heroku Scheduler(适合免费用户)
无需保持Dyno持续运行,通过Heroku定时触发脚本:
- 整理脚本为独立执行文件(如
update-bio.js),移除node-cron相关代码,在脚本末尾添加:main().catch(err => console.error(err)); - 在Heroku控制台启用"Scheduler"插件,添加定时任务:
- 频率选择
Every 6 hours - 命令输入
node update-bio.js
- 频率选择
- 同样通过Heroku配置环境变量存储账号密码。
内容的提问来源于stack exchange,提问作者JazzTGB145
相关产品推荐
相关产品推荐

