@convex-dev/crons

中文文档
0.2.3发布于 2026/10/10Apache-2.0TypeScriptES Module近 30 天下载 35.7万

Convex component for scheduling periodic jobs.

原始使用文档
文档目录4 节
  1. Design
  2. Pre-requisite: Convex
  3. Installation
  4. Usage

Crons Convex Component

npm version

This Convex component provides functionality for registering and managing cron jobs at runtime. Convex comes with built-in support for cron jobs but they must be statically defined at deployment time. This library allows for dynamic registration of cron jobs at runtime.

// Register a cron to run once per day.
const daily = await crons.register(
  ctx,
  { kind: "cron", cronspec: "0 0 * * *" },
  internal.example.logStuff,
  { message: "daily cron" },
);

// Register a cron to run every hour.
const hourly = await crons.register(
  ctx,
  { kind: "interval", ms: 3600000 },
  internal.example.logStuff,
  { message: "hourly cron" },
);

It supports intervals in milliseconds as well as cron schedules with the same format as the unix cron command:

 *  *  *  *  *  *
 ┬  ┬  ┬  ┬  ┬  ┬
 │  │  │  │  │  |
 │  │  │  │  │  └── day of week (0 - 7, 1L - 7L) (0 or 7 is Sun)
 │  │  │  │  └───── month (1 - 12)
 │  │  │  └──────── day of month (1 - 31, L)
 │  │  └─────────── hour (0 - 23)
 │  └────────────── minute (0 - 59)
 └───────────────── second (0 - 59, optional)

Design

The design of this component is based on the Cronvex demo app that's described in this Stack post.

Pre-requisite: Convex

You'll need an existing Convex project to use the component. Convex is a hosted backend platform, including a database, serverless functions, and a ton more you can learn about here.

Run npm create convex or follow any of the quickstarts to set one up.

Installation

Install the component package:

npm install @convex-dev/crons

Create a convex.config.ts file in your app's convex/ folder and install the component by calling use:

// convex/convex.config.ts
import { defineApp } from "convex/server";
import crons from "@convex-dev/crons/convex.config.js";

const app = defineApp();
app.use(crons);

export default app;

Usage

A Crons wrapper can be instantiated within your Convex code as:

import { components } from "./_generated/api";
import { Crons } from "@convex-dev/crons";

const crons = new Crons(components.crons);

The Crons wrapper class provides the following methods:

  • register(ctx, schedule, fn, args, name?): Registers a new cron job.
  • get(ctx, { name | id }): Gets a cron job by name or ID.
  • list(ctx): Lists all cron jobs.
  • delete(ctx, { name | id }): Deletes a cron job by name or ID.

Example usage:

import { v } from "convex/values";
import { internalMutation } from "./_generated/server";
import { internal } from "./_generated/api";

// Dummy function that we're going to schedule.
export const logStuff = internalMutation({
  args: {
    message: v.string(),
  },
  handler: async (_ctx, args) => {
    console.log(args.message);
  },
});

// Run a bunch of cron operations as a test. Note that this function runs as a
// transaction and cleans up after itself so you won't actually see these crons
// showing up in the database while it's in progress.
export const doSomeStuff = internalMutation({
  handler: async (ctx) => {
    // Register some crons.
    const namedCronId = await crons.register(
      ctx,
      { kind: "interval", ms: 3600000 },
      internal.example.logStuff,
      { message: "Hourly cron test" },
      "hourly-test",
    );
    console.log("Registered new cron job with ID:", namedCronId);
    const unnamedCronId = await crons.register(
      ctx,
      { kind: "cron", cronspec: "0 * * * *" },
      internal.example.logStuff,
      { message: "Minutely cron test" },
    );
    console.log("Registered new cron job with ID:", unnamedCronId);

    // Get the cron job by name.
    const cronByName = await crons.get(ctx, { name: "hourly-test" });
    console.log("Retrieved cron job by name:", cronByName);

    // Get the cron job by ID.
    const cronById = await crons.get(ctx, { id: unnamedCronId });
    console.log("Retrieved cron job by ID:", cronById);

    // List all cron jobs.
    const allCrons = await crons.list(ctx);
    console.log("All cron jobs:", allCrons);

    // Delete the cron jobs.
    await crons.delete(ctx, { name: "hourly-test" });
    console.log("Deleted cron job by name:", "hourly-test");
    await crons.delete(ctx, { id: unnamedCronId });
    console.log("Deleted cron job by ID:", unnamedCronId);

    // Verify deletion.
    const deletedCronByName = await crons.get(ctx, { name: "hourly-test" });
    console.log("Deleted cron job (should be null):", deletedCronByName);
    const deletedCronById = await crons.get(ctx, { id: unnamedCronId });
    console.log("Deleted cron job (should be null):", deletedCronById);
  },
});

If you'd like to statically define cronjobs like in the built-in crons.ts Convex feature you can do so via an init script that idempotently registers a cron with a given name. e.g., in an init.ts file that gets run on every deploy via convex dev --run init.

// Register a daily cron job. This could be called from an init script to make
// sure it's always registered, like the built-in crons in Convex.
export const registerDailyCron = internalMutation({
  handler: async (ctx) => {
    if ((await crons.get(ctx, { name: "daily" })) === null) {
      await crons.register(
        ctx,
        { kind: "cron", cronspec: "0 0 * * *" },
        internal.example.logStuff,
        {
          message: "daily cron",
        },
        "daily",
      );
    }
  },
});

Crons are created transactionally and will be guaranteed to exist after the mutation that creates them has run. It's thus possible to write workflows like the following that schedules a cron and then deletes itself as soon as it runs, without any additional error handling about the cron not existing.

// This will schedule a cron job to run every 10 seconds but then delete itself
// the first time it runs.
export const selfDeletingCron = internalMutation({
  handler: async (ctx) => {
    const cronId = await crons.register(
      ctx,
      { kind: "interval", ms: 10000 },
      internal.example.deleteSelf,
      { name: "self-deleting-cron" },
      "self-deleting-cron",
    );

    console.log("Registered self-deleting cron job with ID:", cronId);
  },
});

// Worker function that deletes a cron job.
export const deleteSelf = internalMutation({
  args: { name: v.string() },
  handler: async (ctx, { name }) => {
    console.log("Self-deleting cron job running. Name:", name);
    await crons.delete(ctx, { name });
    console.log("Self-deleting cron job has been deleted. Name:", name);
  },
});

版本与发布记录

@convex-dev/crons 共发布 18 个版本,首次发布于 2024/09/20;过去 12 个月发布了 4 个版本。

版本发布日期距今
0.2.3latest2026/10/101 个月前
0.2.22026/06/254 个月前
0.2.12026/06/035 个月前
0.2.02025/11/1111 个月前
0.1.92025/06/171.4 年前
0.1.82025/05/311.4 年前

其他发布通道:alpha → 0.1.6-alpha.0。

关于 @convex-dev/crons 的常见问题

@convex-dev/crons 是什么?

Convex component for scheduling periodic jobs.

如何安装 @convex-dev/crons?

在项目目录运行 npm install @convex-dev/crons,或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖:convex(^1.24.8)。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖,Yarn 需要手动安装。

@convex-dev/crons 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@convex-dev/crons 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@convex-dev/crons 可以商用吗?

@convex-dev/crons 使用 Apache-2.0 许可。宽松许可:允许商业使用、修改和再分发,并附带明确的专利授权;分发时需保留许可与 NOTICE 文件,修改过的文件要注明改动。以上为概括,不构成法律意见,请以许可原文为准。

@convex-dev/crons 的下载量有多少?

根据 npm 官方下载统计,@convex-dev/crons 在 2026/10/11 – 2026/11/09 这 30 天内被下载 357,125 次,日均约 11,904 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@convex-dev/crons 还在维护吗?

最新版本 0.2.3 发布于 2026/10/10(1 个月前);至今共发布 18 个版本,其中过去 12 个月发布了 4 个;首次发布于 2024/09/20。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。