You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Heroku Scheduler执行Node脚本异常问题排查求助

Heroku Scheduler休眠Dyno不执行任务的解决方案

首先明确:不需要在脚本开头添加请求唤醒Heroku实例——Heroku Scheduler在触发定时任务时,会自动唤醒处于休眠状态的Web Dyno来执行任务。你的问题大概率是其他细节导致的,以下是排查和修复方向:

1. 确认Scheduler的执行命令正确

确保你在Heroku Scheduler中配置的命令是直接调用脚本的正确指令,比如:

node createLottery.js

不要用curl https://your-app.herokuapp.com/xxx这类依赖Web服务的请求——虽然curl也能唤醒Dyno,但如果你的脚本是独立的Node.js脚本,直接用node命令更可靠,避免Web服务启动延迟导致的问题。

2. 修复时区偏差问题

Heroku服务器默认使用UTC时区,你的代码中new Date().getDay()是基于UTC时间判断周几的。如果你期望的是本地时区(比如北京时间)的周日/周三,这里会出现偏差,导致任务执行了但逻辑被跳过,看起来像是没触发。

解决方法:可以转换为目标时区判断周几,比如用原生API处理:

// 示例:转换为北京时间(UTC+8)判断周几
const currentDate = new Date();
const beijingDay = new Date(currentDate.getTime() + 8 * 60 * 60 * 1000).getDay();
// 0=周日,3=周三
if (beijingDay === 0 || beijingDay === 3) {
  // 执行生成逻辑
}

或者使用moment-timezone这类库来更精准处理时区。

3. 修复异步脚本的退出问题

你的脚本最后调用createTime()但没有等待异步操作完成,脚本可能在数据库操作结束前就退出,导致Heroku认为任务完成,但实际逻辑没执行完,日志也会不完整。

修改脚本末尾的调用逻辑,加上错误处理和资源清理:

createTime()
  .catch(err => {
    console.error('任务执行失败:', err);
    process.exit(1); // 非0退出码让Heroku标记任务失败,方便排查
  })
  .finally(() => {
    mongoose.connection.close(); // 关闭数据库连接,避免资源泄漏
    process.exit(0);
  });

4. 去掉冗余的周几判断

既然你已经通过Heroku Scheduler设置了每周日和周三执行任务,脚本里再判断currentDay ===0 || 3属于冗余逻辑,反而可能因为时区问题导致任务白跑。直接去掉这个判断,让Scheduler完全控制执行时间,脚本只负责生成 lottery 数据即可。

5. 检查Dyno资源限制

如果使用的是Heroku免费版Dyno,每月有固定的执行时间配额,耗尽后任务会无法执行。可以在Heroku控制台的「Resources」页面查看Dyno的使用情况,确认配额是否充足。


修改后的完整代码示例

const LotteryModel = require("./models/LotteryModel");
const mongoose = require("mongoose");
require("dotenv").config();

mongoose.set("strictQuery", false);
mongoose.connect(process.env.MONGODB_URI);

const currentDate = () => {
  const date = new Date();
  const day = date.getDate();
  const month = date.getMonth() + 1;
  const year = date.getFullYear();
  return `${day}-${month}-${year}`;
};

const createNumbers = () => {
  let tempArr = [];
  let randomNumber;
  let specialNum = { number: Math.floor(Math.random() * 7) + 1, special: true };
  // 原判断可简化:Math.random()*7+1的范围是1-8,不会出现0
  // if (specialNum.number === 0) specialNum = { number: Math.floor(Math.random() * 7) + 1, special: true };
  
  for (let i = 0; i < 6; i++) {
    let add = true;
    randomNumber = { number: Math.floor(Math.random() * 36) + 1, special: false };

    // 优化重复判断逻辑,用some更高效
    if (tempArr.some(item => item.number === randomNumber.number)) {
      add = false;
    }
    
    if (add) {
      tempArr.push(randomNumber);
    } else {
      i--;
    }
  }
  tempArr.push(specialNum);
  return tempArr;
};

const createTime = async () => {
  console.log("starting function");
  const currentTime = currentDate();
  const findLottery = await LotteryModel.findOne({ lotteryDate: currentTime });
  
  // 如果当天已经生成过,直接退出
  if (findLottery) {
    console.log("今日lottery已存在,无需重复生成");
    return;
  }

  console.log("开始生成lottery数据");
  const allLottery = await LotteryModel.find({});
  const lotteryNumbers = { 
    lotteryNumbers: createNumbers(), 
    lotteryDate: currentTime, 
    id: allLottery.length 
  };
  
  console.log(lotteryNumbers);
  await LotteryModel.create(lotteryNumbers);
  console.log('finish create numbers');
};

// 处理异步执行和错误
createTime()
  .catch(err => {
    console.error('任务执行出错:', err);
    process.exit(1);
  })
  .finally(() => {
    mongoose.connection.close();
    process.exit(0);
  });

内容的提问来源于stack exchange,提问作者Lior98

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.04 21:28:17