PM2 部署 Nodejs 项目,内存满了重启后,项目内定时任务被中断的问题

发布于 1周前 作者 h691938207 来自 nodejs/Nestjs

想请教一下,这种怎么避免定时任务被中断。现在限制 512MB ,4 个进程,然后只在第一个进程跑定时任务。是使用 node-schedule 跑的。现在问题是不稳定,一个月有一两天会被打断,比如 2 点 0 分 0 秒的任务,刚进去任务,内存满载重启,重启后,定时任务不会继续。定时任务时汇总数据的。

目前想到的 一,就是定时任务开启时,先数据库插入记录,如果状态未改变的,重启后,跑方法继续运行。现在怕的是插入数据库的时候被中断,导致还是不会继续任务。

先不打算设置大一点的限制内存,因为服务器 4g ,有 docker 在上面跑着。


PM2 部署 Nodejs 项目,内存满了重启后,项目内定时任务被中断的问题

16 回复

在某个时间段多次检查状态呢


那这个检查的也靠定时器来运作吗?如果少数应该可以,但是这个 sass 系统,生成报表记录有点多,也怕影响系统白天的使用。现在生成报表的全是挤在凌晨的时间。

做个重试策略,redis 写个 key

谢谢,我查一下这个怎么弄

机器不会重启就用 crontab ,机器也不可靠就用外部的 cron 服务区去 call 你的服务。

机器应该不止 512MB 吧,这种情况适合用 MQ 消息队列来完成。

比如定时任务产生消息到 RabbitMQ ,这个基本上是毫秒级别的不会被打断。然后有对应消费者开始处理任务,关掉自动 ack ,只有任务成功或者失败才去确认。这样消费者哪怕被杀死,下次重启还会拿到没有 ack 的消息继续跑。

但是机器的 crontab 或者外部 cron 执行了,项目重启了,不是会一样结果吗?定时任务执行了,但是项目重启了被中断,中断后不会继续执行。

机器 4g ,pm2 分配每个进程限制内存 512MB ,开启了 4 个进程,负载均衡,定时器只在一个进程内运行。

pm2 里的程序只用来分配任务,费内存的任务换到 child_process 执行
要不直接把 node-schedule 换成 bull

谢谢,我去看一下相关内容

3 楼的做法最简单了,在数据一致性的情况下,任务执行往 redis 写个 key ,完成 del 一下,进程 0 启动那里加个查询,拿到 redis 里的 key 执行对应的定时任务就可以了

如果你的期望是恢复任务,那启动的时候检查有没有没完成的任务好了。

重试呀,恢复后检查状态重试

1 任务开启数据库记录个标识,服务启动先检查是否有任务被中断,接着跑
2 写个接口,重启后手动触发

如果加内存的成本比一个工程师的时间价值高,也可以考虑加 swap 。

在使用 PM2 部署 Node.js 项目时,如果内存满了导致进程重启,确实有可能导致项目内的定时任务被中断。这是因为 Node.js 的单线程模型意味着一旦进程终止,所有在该进程内运行的代码,包括定时任务,都会停止。

为了解决这个问题,可以考虑以下几种方法:

  1. 持久化定时任务状态: 使用数据库或外部存储来记录定时任务的状态和下次执行时间。重启后,从存储中读取状态并重新安排任务。

  2. 使用 PM2 的生态系统配置: 在 PM2 的 ecosystem.config.js 文件中,可以配置 restart_delaymax_restarts 来控制重启行为,但这并不能完全解决任务中断的问题。

  3. 使用更可靠的调度器: 考虑使用如 BullAgenda 等基于 Redis 或 MongoDB 的任务队列系统,这些系统可以在 Node.js 进程重启后继续执行任务。

示例代码(使用 Bull 队列):

const Queue = require('bull');
const myQueue = new Queue('myQueue');

myQueue.process(async (job) => {
  // 任务处理逻辑
  console.log('Processing job:', job.data);
});

// 添加任务
myQueue.add({ foo: 'bar' });

使用这样的任务队列系统,即使 Node.js 进程重启,任务也会由队列系统保证继续执行。

总之,对于需要高可靠性的定时任务,建议使用外部的任务队列或调度系统。

回到顶部