# @chamvi/channel-cron 中文文档

规范地址：https://npmcn.com/package/%40chamvi/channel-cron/

版本：0\.8\.0
npm 元数据更新时间：2026-11-08T20:16:11.556Z
中文译文更新时间：2026-11-09T10:13:08.947Z
软件包许可：Apache-2\.0

本文由上游 README 翻译，可能存在偏差，请结合原文核对 API、命令与配置。版权与许可归原作者所有。

原始 npm 页面：https://www.npmjs.com/package/%40chamvi/channel-cron
原文对照：https://npmcn.com/package/%40chamvi/channel-cron/?lang=original
项目主页：https://chamvi.dev/
源码仓库：https://github.com/chamvi/chamvi

## 关键信息（来自 npm 元数据）

- 包体积（解压后）：112 kB，7 个文件
- 模块格式：ES Module
- TypeScript 类型：包内自带
- Node.js 要求：\>=26\.0\.0
- 运行依赖：3 个
- peer 依赖：@chamvi/core ^0\.8\.0
- 首次发布：2026-10-25T08:41:53.860Z
- 最新版本发布：2026-11-08T20:16:11.127Z
- 近 30 天下载量：3465（2026-10-10 至 2026-11-08，npm 官方下载统计）
- 已发布版本数：15（近 12 个月 15 个）

## 中文简介

Chamvi cron频道:每分一分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每一次,每分每分每分每分每分每分每一次,每分每分每分每分每分每一次,每分每分每分每分每分每分每分每一次,每分每分每分每分每分每分一次,一次,每分每分每分每分每分每分每分每分每分每分每.

## 安装

```sh
npm install @chamvi/channel-cron
```

也可以使用：`pnpm add @chamvi/channel-cron`、`yarn add @chamvi/channel-cron`、`bun add @chamvi/channel-cron`

## README

![@chamvi/channel-cron](https://raw.githubusercontent.com/chamvi/chamvi/master/.github/assets/logo.svg)

# @chamvi/频道-cron

**Chamvi cron频道:每分一分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每一次,每分每分每分每分每分每分每一次,每分每分每分每分每分每一次,每分每分每分每分每分每分每分每一次,每分每分每分每分每分每分一次,一次,每分每分每分每分每分每分每分每分每分每分每.**  
每个复制品都登记在同一频道。 商店的锁每分一分,  
同一套装为库伯内特斯克龙乔布发了一发.

[![npm version](https://img.shields.io/npm/v/@chamvi/channel-cron)](https://www.npmjs.com/package/@chamvi/channel-cron) [![CI](https://github.com/chamvi/chamvi/actions/workflows/ci.yml/badge.svg)](https://github.com/chamvi/chamvi/actions/workflows/ci.yml) [![License](https://img.shields.io/npm/l/@chamvi/channel-cron)](https://github.com/chamvi/chamvi/blob/master/packages/channel-cron/LICENSE)

* * *

**目录**

-   [安装](https://npmcn.com/package/%40chamvi/channel-cron/#readme-installation)
-   [使用量](https://npmcn.com/package/%40chamvi/channel-cron/#readme-usage)
-   [滴答滴答的动作](https://npmcn.com/package/%40chamvi/channel-cron/#readme-how-a-tick-works)
-   [重叠政策](https://npmcn.com/package/%40chamvi/channel-cron/#readme-overlap-policies)
-   [时区](https://npmcn.com/package/%40chamvi/channel-cron/#readme-timezones)
-   [关闭](https://npmcn.com/package/%40chamvi/channel-cron/#readme-shutdown)
-   [一发工作](https://npmcn.com/package/%40chamvi/channel-cron/#readme-one-shot-jobs)
-   [选项](https://npmcn.com/package/%40chamvi/channel-cron/#readme-options)
-   [API 密码](https://npmcn.com/package/%40chamvi/channel-cron/#readme-api)
-   [许可证](https://npmcn.com/package/%40chamvi/channel-cron/#readme-license)

## 安装

```bash
npm install @chamvi/channel-cron @chamvi/core --save
```

仅限无害环境管理,节点.js `>=26.0.0`。 。 。 . `@chamvi/core` 是同龄人依赖; [`hubwire`](https://www.npmjs.com/package/hubwire) (车内)和 [`cron-parser`](https://www.npmjs.com/package/cron-parser) 与软件包一起安装.

## 使用量

`cron.on()` 订阅 cron 频道的代理; `cronChannel()` 引擎启动的频道是 :

```typescript
import type { LanguageModel } from 'ai';
import {
    Engine,
    createMemoryStore,
    defineModelAgent,
} from '@chamvi/core';
import { cron, cronChannel } from '@chamvi/channel-cron';

export async function startScheduling(model: LanguageModel) {
    const sweep = defineModelAgent({
        name: 'sweep',
        model,
        instructions: 'Close stale issues older than 30 days.',
        // every 30 minutes, Berlin time; skipped while the previous run is active
        channels: [cron.on('*/30 * * * *', { timezone: 'Europe/Berlin' })],
    });

    // createMemoryStore is per process; with several replicas, pass one shared store
    // (e.g. createDatabaseStore) so its lock fires each tick once across them
    const engine = new Engine({
        store: createMemoryStore(),
        agents: [sweep],
        // every replica registers the same channel; it reads agents and store from the engine
        channels: [cronChannel()],
    });

    // starts the cron channel after recovering runs
    await engine.start();

    // shutdown: drain() stops the channel first, then lets the runs in flight finish
    // await engine.drain();
    return { engine };
}
```

`cron.on(expression, options?)` 验证表达式( cron-parser) 和时区并丢弃 `InvalidAgentDefinitionError` 对于一个它拒绝. `engine.start()` 恢复运行后启动频道: 订阅调度器无法使用的代码( 表达式 croner 拒绝) 的代理失败 `engine.start()` 与 `InvalidAgentDefinitionError` 命名代理和订阅,代理文件夹的地址是 `onError` 留下那个特工 其他频道的订阅被忽略. 该频道跟随在运行时间注册,替换并移除的代理.

第二个cron信道(例如每个区域一个)需要自己的名称 `on()` 只让订阅点火:

```ts
const eu = cronChannel({ name: 'cron-eu' });
defineModelAgent({ name: 'digest', channels: [eu.on('0 8 * * *', { timezone: 'Europe/Berlin' })] /* ... */ });
new Engine({ channels: [cronChannel(), eu] /* ... */ });
```

## 滴答滴答的动作

-   **每个订阅一个部分.** 每一个都变成一个 集线器计划组件 命名 `cron:<agent>:<subscriptionId>`。 。 。 .
-   **每滴一个复制品.** 在滴答运行之前,复制品会获得商店锁 `cron:<agent>:<subscriptionId>:<scheduledAt ISO>` (通过) `ILockRepository`用于 `lockTtlMs` (默认10分). 密钥永远不会被放出:一个晚点放出同一滴的复制品无法再次取胜.
-   **重复发送.** 胜者通过频道发送(信封) `channel` =频道名称, `trigger` = 有效载荷的订阅id) `options.payload ?? { scheduledAt: '<ISO>' }` 和独有性键 `<subscriptionId>@<scheduledAt ISO>`,所以即使同一勾选的第二次射击也返回了现有的运行。 订户自己买的 `idempotencyKey()` 被忽略为克龙.
-   **从来没有开始.** 启动或重新启动复制点火无事可做; 第一次发送是下一个预定的勾选 .
-   **无相接取.** 掉入重启的滴答,或者其计时器起火的滴答 `lockTtlMs` 或更晚(一个已暂停的流程),不会在以后发射.
-   **报告失败,而不是抛出.** 锁定存储失败, 重叠检查或发送到达 `onError(error, { agent, subscription })`;下一勾选正常运行.

## 重叠政策

`cron.on(expression, { overlap })` 设置策略; 频道在发送前执行。 "Active"的意思是同一订阅的一跑在 `queued`, (中文(简体) ), `running`, (中文(简体) ), `waiting` 或者说 `interrupted`。 。 。 .

| 政策 | 选中值跳过时 | 默认 `concurrencyKey` |
| --- | --- | --- |
| `skip` (默认) | 任何订阅运行已激活 | 订阅编号 |
| `queue-one` | 订阅的一连串仍然 `queued` | 订阅编号 |
| `allow` | 永远 | 无 |

A 类 `concurrencyKey()` 在订阅时胜过默认。 默认密钥是 `queue-one` 等待 : 引擎每次启动一次运行, 一次启动密钥, 所以队列运行在活动者和解时启动 。 这也使得比赛变得无害:在之前的滴滴调度还在飞行中时进行检查的勾子可能会发出第二次跑道,然后等待而不是同时跑道.

## 时区

`cron.on(expression, { timezone: 'Europe/Berlin' })` 取IANA区;没有IANA区,则应用过程的局部区. 在 DST 更改时 :

-   当地时间发生两次(倒回)火灾一次,第一次发生时.
-   当地时间春前变化跳过火灾一次,一小时后当地时间(`30 2 * * *` 3点半起火).

## 关闭

`engine.drain()` (和 `engine.stop()`)首先停止航道(没有新的滴入;飞行完成时滴入),然后排出跑道:

```ts
await engine.drain(); // stops the cron channel, waits for running runs, then interrupts the rest
```

## 一发工作

`runJob()` 开出一次Cron订阅 等待它的运行, 一个Kubernetes CronJob 而不是一个长寿的复制品:

```ts
const { exitCode } = await runJob({ engine, agent: sweep });
process.exitCode = exitCode;
```

它在当前时间发送勾选( 重叠策略适用) , 启动引擎 `start({ channels: false })` (所以一个工作从不开始 cron 调度或其他渠道) 并运行一个批准勾选(当勾选被跳过时) , 等待到运行 `completed`, (中文(简体) ), `failed`, (中文(简体) ), `cancelled` 或者说 `waiting`,或 `queued` 背着同样的订阅 等待批准,然后打电话 `engine.drain()`。引擎必须持有订阅的 cron 通道(它拒绝代理).

| 结果 | `status` | `exitCode` |
| --- | --- | --- |
| 运行完成 | `completed` | `0` |
| 跑步要等批准 | `waiting` | `0` |
| 跑步等待跑步暂停等待批准(`queue-one`(中文(简体) ) | `queued` | `0` |
| 重叠策略跳过勾选 | `skipped` | `0` |
| 运行失败或取消 | `failed`, (中文(简体) ), `cancelled` | `1` |

暂停审批的跑步不持有吊舱:工作返回,批准得到回答(或时断出),被答复的跑步由长生复制或下个工作吊舱执行,即使自己的滴滴被跳过也会启动引擎. 这个吊舱还恢复了一次运行 吊舱被杀死 并否认批准过他们的超时。 洞穴:

-   `engine.start()` 追回和执行 **每个** 已排队运行 **每个** 代理在共享商店, 不仅仅是克龙运行.
-   `drain()` 中断任何仍在运行的 `drainTimeoutMs`。 。 。 . `runJob` 等待它发送的运行, 所以剩余运行完成 由长寿的复制品 或后期的工作舱, 在该舱内 `drainTimeoutMs`。 。 。 .
-   大小 `drainTimeoutMs` 更喜欢长期部署 `cronChannel()` 当运行是漫长的.

## 选项

`cronChannel(options)`数字 :

| 选项 | 类型 | 默认 | 说明 |
| --- | --- | --- | --- |
| `name` | `string` | `'cron'` | 频道名称; `on()` 认购 |
| `owner` | `string` | `` `${hostname}-${pid}` `` | 锁主 |
| `lockTtlMs` | `number` | `600_000` | 抓住一滴锁键多久; 迟或迟发射一滴 |
| `onError` | `(error, { agent, subscription }) => void` | `console.error` | 失败的勾选和代理文件夹的不可更改订阅 |

`cron.on(expression, options)`数字 :

| 选项 | 类型 | 默认 | 说明 |
| --- | --- | --- | --- |
| `timezone` | `string` | 本地区域 | IANA区 |
| `overlap` | `'skip' | 'queue-one' | 'allow'` | `'skip'` | 见 [重叠政策](https://npmcn.com/package/%40chamvi/channel-cron/#readme-overlap-policies) |
| `payload` | `unknown` | `{ scheduledAt }` | 跑者的有效载荷 |
| `id` | `string` | `` `cron:${expression}` `` | 订阅 id, 每个代理独有 |

`runJob(options)`数字 :

| 选项 | 类型 | 默认 | 说明 |
| --- | --- | --- | --- |
| `engine` | `IEngine` | 所需经费 | 尚未开始; 开始时没有渠道, 并且被工作耗尽, 也当勾选跳过时。 它的钟给 `scheduledAt` 并驱动民意调查 |
| `agent` | `Agent` | 所需经费 | 开枪的特工 |
| `subscription` | `string` | 唯一的 crun 订阅 | Cron 订阅 ID; 当代理机有多个时需要 |
| `pollMs` | `number` | `1_000` | 选票 `engine.getRun`,它也看到运行完成 由另一个复制 |
| `drainTimeoutMs` | `number` | `30_000` | 传到 `engine.drain()` |
| `signal` | `AbortSignal` | 无 | 停止任务( 参见类型文件) |

## API 密码

| 导出 | 仁爱 | 目的 |
| --- | --- | --- |
| `cronChannel` | 函数 | 克龙频道; `engine.start()` 开始, `drain()` 停下来; `.on()` 认购 |
| `cron` | 对象 | `cron.on(expression, options?)`: 默认的订阅 `cron` 频道 |
| `runJob` | 函数 | 开出一次Cron订阅 等待运行 |
| `fireCronSubscription` | 函数 | 一个勾选符:对某个特定的重复检查和发送 `scheduledAt` |
| `readCronOptions` | 函数 | 读取并验证选项 `cron.on()` 订阅存储 |
| `assertSchedulable` | 函数 | 丢弃用于订阅 crun 频道( 默认) `cron`调度器无法使用 |
| `createRepositoryScheduleLock` | 函数 | 接线 `IScheduleLock` 超过核心 `ILockRepository` |
| `CRON_CHANNEL_NAME` | 常数 | `'cron'` |
| `SCHEDULE_LOCK_TTL_MS` | 常数 | 默认锁定 TTL, `600_000` |

类型 : `CronChannel`, (中文(简体) ), `CronChannelOptions`, (中文(简体) ), `CronChannelErrorContext`, (中文(简体) ), `CronSubscriber`, (中文(简体) ), `CronSubscriptionOptions`, (中文(简体) ), `OverlapPolicy`, (中文(简体) ), `RunJobOptions`, (中文(简体) ), `RunJobResult`, (中文(简体) ), `CronOptions`, (中文(简体) ), `CronTickContext`, (中文(简体) ), `CronTickResult`, (中文(简体) ), `CronTickDispatched`, (中文(简体) ), `CronTickSkipped`。 。 。 .

## 许可证

原载 [Apache 许可证 2.0](https://npmcn.com/package/%40chamvi/channel-cron/LICENSE)。 。 。 .

## 常见问题

### @chamvi/channel-cron 是什么？

Chamvi cron频道:每分一分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每分每一次,每分每分每分每分每分每分每一次,每分每分每分每分每分每一次,每分每分每分每分每分每分每分每一次,每分每分每分每分每分每分一次,一次,每分每分每分每分每分每分每分每分每分每分每\.

### 如何安装 @chamvi/channel-cron？

在项目目录运行 npm install @chamvi/channel-cron，或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖：@chamvi/core（^0\.8\.0）。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖，Yarn 需要手动安装。

### @chamvi/channel-cron 支持 TypeScript 吗？

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

### @chamvi/channel-cron 支持 ESM 还是 CommonJS？

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

### @chamvi/channel-cron 需要什么版本的 Node\.js？

package\.json 的 engines 字段要求 Node\.js \>=26\.0\.0。版本不符时 npm 默认只给出警告，开启 engine-strict 后会拒绝安装。

### @chamvi/channel-cron 可以商用吗？

@chamvi/channel-cron 使用 Apache-2\.0 许可。宽松许可：允许商业使用、修改和再分发，并附带明确的专利授权；分发时需保留许可与 NOTICE 文件，修改过的文件要注明改动。以上为概括，不构成法律意见，请以许可原文为准。

### @chamvi/channel-cron 的下载量有多少？

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

### @chamvi/channel-cron 还在维护吗？

最新版本 0\.8\.0 发布于 2026/11/09（今天）；至今共发布 15 个版本，其中过去 12 个月发布了 15 个；首次发布于 2026/10/25。发布频率只是参考信号：功能稳定的工具可能很少需要更新，建议结合源码仓库的 issue 和提交记录判断。

