全新推出的 Deno 定时任务功能

构建网络应用变得越来越复杂。编写现代软件包括利用云基础设施、解析样板代码以及管理复杂的配置,而开发人员只想专注于编写业务逻辑。

Deno 的目标是通过消除配置和不必要的样板代码,从根本上简化 web 开发。我们已经构建了 Deno KV,一个无服务器数据库,以及 Deno Queues,一种用于卸载任务或计划未来工作的方式,直接集成到运行时中,因此将它们添加到您的应用程序只需要几行代码。

今天,我们很高兴通过引入 Deno Cron 来迈出简化 web 开发的又一步,这是创建定时任务的一种简便方法:

Deno.cron("hello", "*/10 * * * *", () => {
  console.log("这将每 10 分钟运行一次");
});

使用 Deno Cron

Deno.cron()(截至版本 1.38,可通过 --unstable 标志启用)是一个接受三个参数的函数:

  • name,您的定时任务的名称
  • schedule,使用 Unix cron 格式,时间为 UTC 时区
  • handler,根据提供的时间表执行的函数

与 UNIX/Linux 上的 cron 不同,Deno Cron 的执行不会重叠。这意味着如果您安排每 10 分钟运行一次的任务,但任务需要 30 分钟才能完成,Deno Cron 会自动跳过下一个预定的运行,直到任务完成。重叠的 cron 作业可能导致意外问题,并需要额外的繁琐逻辑来避免,但Deno Cron 完全避开了这个问题。

我们还在努力支持一个友好的 JavaScript API 用于指定 cron 时间表。

在 Deno Deploy 上使用 Deno Cron

在 Deno Deploy 上,我们的多租户分布式无服务器 JavaScript 平台,Deno.cron() 会被自动检测和管理,因此您无需担心任何事情。

您可以在没有 web 服务器甚至连续传入请求的情况下运行 cron 作业,以保持您的隔离环境处于活动状态。这是因为每当部署项目时,Deno Deploy 会自动检测您的 cron 作业并对其进行评估。当处理程序运行时,Deno Deploy 会自动按需启动一个隔离环境来运行它们。

Deno.cron("hello", "*/1 * * * *", () => {
  console.log("每分钟,Deno Deploy 在没有服务器的情况下运行这个");
});

我们还在 Deno Deploy 仪表板中添加了一个新的 Cron 选项卡,显示项目中的所有活动 cron 作业:

项目中显示所有活动 cron 作业的新 cron 选项卡。

您的 cron 作业将显示在日志中。

要修改或停止现有的 cron,更改您的代码并创建一个新的部署。例如,如果从代码中删除了 Deno.cron 并部署了它,那些作业将不再被安排运行。

您的 Deno Cron 处理程序可以执行各种操作,如在 Deno KV 中更新状态、ping 网站、发送电子邮件、启动数据库备份、定期调用 API 等等。

在 Deno Deploy 上是如何运作的?

在没有 Web 服务器处理请求的情况下,Deno Deploy 是如何知道你的代码中存在 cron 任务的呢?

当创建项目的新生产部署时,会使用一个临时的 V8 隔离环境来评估项目的顶层作用域,并查找任何 Deno.cron 的定义。然后,全局的 cron 调度程序会更新为项目最新的 cron 定义,其中包括对现有 cron 的更新、新的 cron 和已删除的 cron。

全局的 cron 调度程序是一个可靠的服务,负责根据指定的计划安排和分发 cron 任务。在分发过程中,会启动一个按需的 v8 隔离环境来使用相同的生产部署执行任务。

const db = await Deno.openKv();

// 小时级 cron 任务,将天气数据时序写入 Deno KV
Deno.cron("Write weather data to Deno KV", "0 * * * *", async () => {
  console.log("拉取天气数据并写入 Deno KV");
  const res = await fetch('https://api.open-meteo.com/v1/forecast?latitude=34.0522&longitude=-118.2437&hourly=temperature_2m,precipitation&timezone=America%2FLos_Angeles');
  const body = await res.json();
  const date = new Date(Date.now()).toString();
  await db.set(["weather", date], {
      temperature: body.hourly.temperature_2m[0],
      precipitation: body.hourly.precipitation[0]
    }
  );
});

// HTTP 服务器获取天气数据时序
Deno.serve(async (_req) => {
  const entries = db.list({ prefix: ["weather"] });
  let responseString = "";
  for await (const entry of entries) {
    responseString += `${entry.key[1]}: ${entry.value.temperature}°C,降水量 ${entry.value.precipitation}mm\n`;
  }
  return new Response(responseString);
})

在 Deno Deploy 上使用 Deno Cron,可以轻松创建 cron 任务,并在云端主机上在几分钟内进行托管,无需任何配置。

1 个赞
Deno.cron("sample cron", "*/1 * * * *", () => {
  console.log(new Date());
});

image

new Date()会存在额外开销,Deno.cron无法获取当前或下一次任务时间nextDate。
期望得到下面数据

2023-12-14T07:51:00.000Z
2023-12-14T07:52:00.000Z
2023-12-14T07:53:00.000Z
2023-12-14T07:54:00.000Z
2023-12-14T07:55:00.000Z
2023-12-14T07:56:00.000Z
2023-12-14T07:57:00.000Z

这个没法实现,代码执行的开销是客观存在的

node-cron
可以通过nextDate或nextDates获取到准确的执行时间

这就需要改 api 的设计了

很赞的样子

Deno deploy 创建v8 隔离环境是用的web worker吗?还是别的呀?

v8 isolate context