随着时间的流逝,每隔2分钟运行一次Nodejs函数

时间:2019-07-08 12:36:48

标签: javascript node.js typescript

这是很难描述的问题。 我有一个koajs应用,该应用的功能是每2分钟在多个实例(10-1000范围)中创建的。在应用启动时创建的计划作业。我使用koajs是因为我为此应用程序需要一些简单的api端点。在开始的3-5个小时内运行良好,然后创建的实例数开始减少,某些日志输出消失了。

这是基于实际代码的最少示例:

server.ts

const bootstrap = async () => {
    process.setMaxListeners(0); //(node:7310) MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 11 uncaughtException listeners added to [process]. Use emitter.setMaxListeners() to increase limit
                                //appears on app startup (however seems like this setMaxListeners(0) doesnt affect anything since the warning persist)
    const app = new Koa();
    app.use(async ctx => {
        ctx.body = "Welcome to my Server!";
    });
    app.listen(port);
    new Main().run();
};

bootstrap(); 

main.ts (尝试使用cron npm软件包,node-schedulersetInterval,递归setTimeout)来运行{{1} }。

scheduledJobWrapper

在此示例中,问题表现如下: 预期的所有工作在最初的3-5小时内进行,之后每次计划的功能调用:

  1. isStarting: boolean = false; async run() { logger.info(`running the app, every 2 minutes`); //let that = this; // new CronJob(`*/2 * * * *`, function () { // that.scheduledJobWrapper(); // }, null, true, 'America/Los_Angeles'); const interval = 2 * 60 * 1000; setInterval(() => { this.scheduledJobWrapper(); }, interval); } async scheduledJobWrapper() { logger.info("here scheduledJobWrapper"); let args = {}; //some irrelevant logic to set the arguments await this.scheduledJob(args); } async scheduledJob(args) { try { logger.info("starting"); if (!this.isStarting) { this.isStarting = true; const runningCount = Executor.tasks.length; //Executor.tasks is a singleton containing some info about tasks. details are irrelevant. the point is it contains the active tasks. const tasksLimit = 100; if (runningCount < tasksLimit) { for await (const i of Array(tasksLimit - runningCount).keys()) { if (Executor.tasks.length > 20) await global.sleep(5 * 1000); this.startWrapper(args); //calling main task here } } this.isStarting = false; logger.info(`Started: ${Executor.tasks.length - runningCount}`); } } catch (e) { logger.error("Error running scheduled job: " + e.toString()); } } 现在不会显示任何输出。
  2. logger.info("here scheduledJobWrapper");不在输出中
  3. logger.info("starting");确实运行,并且其中的代码正在执行。

尽管this.startWrapper内部的代码仍在运行,但是新创建的作业的数量正在缓慢减少。 硬件(RAM / CPU)负载不大(CPU低于10%,RAM低于20%)

关于可能原因的任何线索吗?

谢谢!

更新 似乎使用this.startWrapper时,该应用程序可以正常运行更长的时间(6-24小时),但此后问题仍然开始。

2 个答案:

答案 0 :(得分:1)

问题与setInterval函数有关。随着时间的流逝,它变得越来越慢。它也有奇怪的行为。您可以使用setTimeout创建自定义setInterval或使用第三方模块并进行尝试。

setInterval实现示例。

const intervals = new Map();
function setInterval(fn, time, context, ...args) {
  const id = new Date().getTime() + "" + Math.floor(Math.random() * 10000);
  intervals.set(
    id,
    setTimeout(function next() {
      intervals.set(id, setTimeout(next, time));
      fn.apply(context, args);
    }, time)
  );
  return id;
}
function clearInterval(id) {
  clearTimeout(intervals.get(id));
}

setInterval(console.log, 100, console, "hi");

您还可以通过在下一个setTimeout中添加增量时间损失来增强功能。 这意味着如果浪费时间,请更早运行下一个setTimeout。

答案 1 :(得分:0)

首先,最好在侦听范围内移动Main()的实例:

app.listen(port, () => {
   new Main().run();
});

我不知道在后端运行setInterval函数有什么好主意。最好提取此逻辑并将其移入cron作业。

我们确定机器可以运行100个任务吗?请按顺序计数任务,并查看问题何时开始。可能您无法安排100个任务,并且某个地方存在一个限制