• 分享七款最常见的Node.js作业调度器
  • 发布于 2个月前
  • 93 热度
    0 评论
作业调度是在特定时间或特定事件发生时启动作业、任务或函数的过程。类 Unix 系统中使用的基于时间的作业调度程序 Cron 是大多数作业调度程序的基础。Node.js 运行时环境有许多作业调度程序可用。其中一些调度程序同时在浏览器和 Node 中运行,另一些则只在 Node 中运行。由于这些调度程序各有特点,因此在我们给应用程序选择最佳调度程序将是一项具有挑战和耗时的工作。

在本文中,我们将向您介绍最常见的 7 种 Node.js 作业调度器,重点介绍它们的重要特性、不同点和相同点。除了调度器提供的主要特性和功能外,我们还将重点介绍一些有用的指标和信息,如软件包大小、GitHub star 数、发布次数、npm 下载量、软件包许可证、依赖性和维护等。在文章的第二部分将介绍 node-schedule 在项目中的应用实践。

1.流行的 Node.js 调度器
截止到本文发稿时,常见的 Node.js 调度器有 Node-Schedule、Node-Cron、Agenda、Bree、Cron、Bull、Bottleneck,下面将从不同角度来介绍它们的重要特性和异同点。

首先来看看 NPM Trends 对比:

1.1.Bottleneck
Bottleneck 是一款适用于 Node.js 和浏览器的轻量级零依赖任务调度器和速率限制器。它是一种简单的解决方案,因为它几乎不会增加代码的复杂性。它是经过实战检验的、可靠的、生产就绪的,已在私营公司和开源软件中大规模使用。

从 NPM 下载量可以看到,Cron 是第一大常用的 Node.js 调度工具。它支持集群,可以在多个 Node.js 实例之间对作业进行速率限制。它使用 Redis 和严格的原子操作,在客户端和网络不可靠的情况下也能保持可靠。它还支持 Redis Cluster 和 Redis Sentinel。

大多数应用程序接口都有速率限制。例如,每秒处理三个请求:
const limiter = new Bottleneck({
    minTime: 333
});
如果您希望阻止多个请求同时运行,并且某些请求的运行时间可能超过 333ms,请添加 maxConcurrent: 1:
const limiter = new Bottleneck({
    maxConcurrent: 1,
    minTime: 333
});
Bottleneck 可创建任务队列并快速完成任务。默认情况下,任务通常会按照收到的顺序执行。

1.2.Cron
Cron 是一款功能强大的工具,可根据使用 cron 语法定义的时间表运行作业(函数或命令)。它非常适合数据备份、通知等任务。但使用时需要注意的是,Cron 和 下面将要介绍的 Node-cron 的 GitHub 仓库名称都是 node-cron,仅仅是 npm 包名不同。从 NPM 下载量可以看到,Cron 是第二大常用的 Node.js 调度工具,拥有 8k Github star,在当前最新版本为 3.1.6 之前,已经发布了 60 个版本。

主要特性如下:
.在计划任务触发时执行函数
.使用 child_process 执行 javascript 进程外部的任务(如系统命令
.使用日期或 Luxon DateTime 对象(而非 cron 语法)作为回调触发器
.使用额外的秒槽(不使用时默认为 0,与 Unix 行为一致)
具体用法:
import { CronJob } from 'cron';
// 堆代码 duidaima.com
const cronJob = new CronJob('* * * * * *', () => {
  console.log('You will see this message every second');
 },
 null,
 true,
 'America/Los_Angeles'
);

1.3.node-schedule
node-schedule 是一款适用于 Node.js 的多功能作业调度程序,其工作方式既像 cron,又不像 cron。通过可配置的递归标准,它能让你安排作业(任意函数)在特定日期执行。它不会每秒或每分钟评估即将到来的作业,每次只使用一个计时器。node-schedule 不使用基于时间间隔的调度,而是使用基于时间的调度。

这是一款获得 MIT 许可的 Node.js 作业调度开源工具。根据 npm 下载量,它是第三大最常用的 Node 调度工具。多年来,node-schedule 有很多机会进行调整和改进,在当前的 2.1.0 版本之前,它已发布了 44 个版本。尽管 node-schedule 也可以灵活使用,但它主要用于基于时间的调度,而不是基于间隔的调度。借助 node-schedule,您可以快速安排一个任务在特定日期运行,并提供可选的循环配置。

您可以选择在 node-schedule 中使用基于日期的调度和基于 cron 表达式的调度。当使用基于 cron 表达式的调度时,您可以传递一个 cron 表达式,并使用 cron-parser 解析它来指示何时触发作业:
const nodeSchedule = require('node-schedule');

const job = nodeSchedule.scheduleJob('* * * * *', function() {
  console.log('Job has been triggered at: ', new Date.toLocaleTimeString());
});
相反,基于日期的调度允许您传递一个真实的JavaScript日期对象,以确定作业的特定执行日期。此外,它还提供了在未来使用的选择,以绑定当前数据。与大多数 Node.js 调度程序一样,node-schedule 有一个限制,即只有在脚本处于活动状态时才会触发作业。如果您想安排一个在脚本不活动时仍然继续执行的作业,请考虑使用 Cron。同样,如果您希望在重启之间保留作业,这可能不是一个好的选择。

1.4.Bull
Bull 是 Node.js 的队列系统,它使用必须运行 Redis 服务器。如果不想使用 Redis,就只能使用其他调度程序。如果你不想在系统上安装 Redis,也可以使用与 Bull 完美集成的 Redis 托管服务。

Bull 是 Node 运行环境中最快速、最可靠的基于 Redis 的队列系统。这个获得 MIT 许可的软件包每周有 421 580 次下载,发布于九年前。它目前的版本是 4.11.5,仍在持续迭代,这进一步说明它还是比较成熟和可靠的。

除其他功能外,Bull 还提供基于 cron 语法的作业调度、作业速率限制、并发性、每个队列运行多个作业、重试和作业优先级。看一个实例:
const Queue = require('bull');

const helloWorldQueue = new Queue('hello-world-queue');
const data = {
  someData: 'Hello World!'
};
const options = {
  delay: 5000,
  attempts: 3
};

helloWorldQueue.add(data, options);
helloWorldQueue.process((job) => {
  console.log(job.data.someData);
});
1.5.Node-Cron
node-cron 模块是基于 GNU crontab 的 node.js 纯 JavaScript 小型任务调度程序。该模块允许您使用完整的 crontab 语法在 node.js 中调度任务。如果你需要支持工作线程和 cron 语法的作业调度程序,建议试试 Bree 作业调度器!
const nodeCron = require('node-cron');

nodeCron.schedule('* * * * * *', () => {
  // This job will run every second
  console.log(new Date().toLocaleTimeString());
})
除了调度作业的 schedule 方法外,Node-cron 还包括验证 cron 表达式、开始、停止和终止计划作业的方法。如果你需要在 Node 或服务器端调度一个简单的作业,Node-cron 会很有帮助,但如果你还需要一个支持工作线程或在浏览器中运行的调度程序,建议你试试 Bree。

1.6.Agenda
Agenda 提供了使用 cron 和更易理解的语法灵活调度作业的能力。要将 Agenda 用作作业调度程序,必须运行 MongoDB 数据库。如果不想在系统中下载和安装 MongoDB,可以创建一个 Docker 容器或使用 MongoDB 的云数据库 Atlas 来试用此调度程序。如果你不想使用 MongoDB,那么这个软件包可能并不适合你。

下面的代码示例,每分钟向控制台记录一次日志:
const mongoConnectionString = "mongodb://127.0.0.1/agenda";
const agenda = new Agenda({
  db: {
    address: mongoConnectionString
  }
});

agenda.define("Delete old users", async (job) => {
  await User.remove({
    lastLogIn: {
        $lt: twoDaysAgo
    }
  });
});
(async function() {
  // IIFE to give access to async/await
  await agenda.start();
  await agenda.every("3 minutes", "Delete old users");

  // Alternatively, you could also do:
  await agenda.every("*/3 * * * *", "Delete old users");
})();
Agenda 是一个 Node 调度器,已获得 MIT 许可。它最初发布于八年前,最新版本为 5.0.0。它在 GitHub 上有 9.1k 的 star。Agenda 是一个相当复杂的软件包,它有很多功能,但也有很多依赖项。

1.7.Bree
Bree 是另一款获得 MIT 许可的 JavaScript 作业调度程序。Bree 是 Node.js 和 JavaScript 的最佳作业调度程序,支持 cron、日期、毫秒、稍后和人性化功能,在Node 和浏览器都可用于运行它。与上面提到的其他调度程序相比,这个软件包相当新,迭代也比较频繁,自首次发布以来,已有约 97 个版本发布。
// app.mjs

import Bree from 'bree';

const bree = new Bree({
  // ... (see below) ...
});

// top-level await supported in Node v14.8+
await bree.start();

// ... (see below) ...
二.node-schedule 应用实践
小懒在项目中使用的是 node-schedule 调度器,选择它的原因是比较喜欢它的 Cron 风格,和 crontab 比较类似,上手成本较低。
* * * * * *
┬ ┬ ┬ ┬ ┬ ┬
│ │ │ │ │ |
│ │ │ │ │ └ day of week (0 - 7) (0 or 7 is Sun)
│ │ │ │ └───── month (1 - 12)
│ │ │ └────────── day of month (1 - 31)
│ │ └─────────────── hour (0 - 23)
│ └──────────────────── minute (0 - 59)
└───────────────────────── second (0 - 59, OPTIONAL)
2.1.初始化项目
npm init -y

# 安装依赖
npm i node-schedule
创建 index.js 并增加如下内容:
const http = require('node:http');
const schedule = require('node-schedule');
const server = http.createServer();
const port = 8889;

// Listen to the request event
server.on('request', (request, res) => {
  res.writeHead(200, { 'Content-Type': 'application/json' });
  res.end(JSON.stringify({
    data: 'demo',
    env: process.env.NODE_ENV || 'development',
  }));
});

server.listen(port, () => {
  console.log(`http://localhost:${port}`);
});
2.2.创建调度任务
在 index.js 中增加如下调度任务:
const job01 = schedule.scheduleJob('49 * * * *', function(){
  console.log('每 49 分执行一次动作');
});

const job02 = schedule.scheduleJob('*/2 * * * * *', function(){
  console.log('每 2s 执行一次动作');
});

const job03 = schedule.scheduleJob('20 * * * * *', function(){
  job02.cancel();
  job03.cancel();
  console.log('20 秒取消 job02 循环调度,取消 job03');
});
总结
Node.js 生态提供了多种调度器可供开发者使用。在实际使用时,需要结合自己项目特点和具体需求选择能满足您基本需求的调度器。如果你想在服务器端执行简单易行的工作调度,Cron、Node-cron 和 Node-schedule 可能值得考虑,因为它们简单、成熟、流行、可靠。Agenda 和 Bull 也提供了简单的任务调度,在数据库持久性方面提供额外的功能和帮助。

另一方面,如果您正在寻找一款具有额外功能的调度程序,如支持在浏览器和 Node 中运行(除基本作业调度外),那么 Bree 可能是您的最佳选择。
用户评论