# 设置和管理计划任务（Cron Jobs）

Source: https://support.kapsulehost.com/zh-cn/cron-jobs

Cron 任务会按计划在后台运行一个命令,无论是否有人正在访问您的网站。本指南将介绍如何在 KPanel 中添加 Cron 任务、为该平台正确编写计划和命令、替换 WordPress 不可靠的内置调度程序,以及在某个任务未按预期执行时查找其输出内容。

## Cron 在 KPanel 中的位置

Cron 属于某个站点,因此您需要从该站点进入,而不是从主菜单进入:

1. 登录 [KPanel](https://kpanel.kapsulehost.com),然后点击左侧边栏中的 **网站**。
2. 点击您要操作的站点。
3. 在该站点自己的菜单中,打开 **设置**,然后打开 **Cron**。

直接访问地址为 `/websites/<site-id>/cron`。您将看到现有任务的列表,如果该站点没有任何任务,则会显示空状态。

![KPanel 中某站点的 Cron 页面,列出了该站点上的计划任务](https://support.kapsulehost.com/help/screenshots/cron-jobs.13aef775.webp)

## 添加任务

点击右上角的 **添加计划任务**。表单包含三个字段。

### 计划

六个预设按钮可为您自动填写表达式:

| 按钮 | 表达式 |
|---|---|
| 每分钟 | `* * * * *` |
| 每 5 分钟 | `*/5 * * * *` |
| 每小时 | `0 * * * *` |
| 每日凌晨2点 | `0 2 * * *` |
| 每周日 | `0 2 * * 0` |
| 每月 1 号 | `0 2 1 * *` |

或者在 **Cron 表达式** 中输入您自己的表达式。按顺序排列的五个字段分别为:分钟、小时、日期、月份、星期:

```
minute  hour  day-of-month  month  day-of-week
```

- `0 3 * * *` 每天凌晨 3 点运行。
- `*/15 * * * *` 每十五分钟运行一次。
- `0 9 * * 1` 每周一上午 9 点运行。
- `30 1 1 * *` 每月 1 日凌晨 1 点 30 分运行。
- `0 */6 * * *` 每六小时在整点运行一次。

### 标签

一个您日后能够识别的名称,例如 `WordPress cron` 或 `Nightly stock sync`。这是任务列表中显示给您的内容,因此请让它具有描述性:凌晨 2 点时,`job 3` 这样的名称对任何人都没有帮助。

### 命令

要运行的 shell 命令。点击 **Save** 以创建该任务。

> **Warning:** 请使用完整路径。Cron 运行时使用的是最基本的环境,不包含您的任何 shell 配置文件,因此单独的 `php` 命令,或是只有在您通过 SSH 登录时才有效的相对目录,在此处都会悄无声息地失败。请每次都写出完整路径。

## 编写命令

任务以您站点自身的系统用户身份运行,因此您的主目录是正确的参照点,`~` 也能正确解析。您的站点文件位于:

```
~/htdocs/yourdomain.co.nz
```

您可以在该站点的 **设置**,然后 **SFTP** 选项卡上确认确切路径,该路径会显示在 **网站文件** 下方。

典型命令:

```
cd ~/htdocs/yourdomain.co.nz && /usr/bin/wp cron event run --due-now
```

```
cd ~/htdocs/yourdomain.co.nz && /usr/bin/php bin/send-queued-emails.php
```

```
/usr/bin/curl -fsS https://yourdomain.co.nz/api/nightly-report
```

> **Tip:** 在设定计划之前,请先测试该命令。如果是 `wp` 命令,请将其粘贴到该站点的 **WordPress**,然后 **Console** 部分;或者通过 SSH 运行它。在命令提示符下发现一个根本行不通的任务,要比凌晨 3 点在日志文件中发现它容易得多。

## 替换 WordPress 的内置调度程序

WordPress 自带一个伪调度程序 WP-Cron,它只在有人加载页面时才会触发。在访问量较少的站点上,计划发布的文章会延迟发布,邮件也会排队未能发送。而在访问量大的站点上,每一位访客都要承担检查计划任务所带来的开销。

真正的 Cron 任务可以同时解决这两个问题。KPanel 会为您完成整个替换过程:

1. 打开该站点,然后打开 **WordPress** 选项卡。
2. 打开 **WP-Cron** 部分。
3. 点击 **启用系统cron**。

这会添加一个每五分钟运行一次 WP-Cron 的计划任务,并设置 `DISABLE_WP_CRON`,从而使页面加载不再触发它。同一屏幕上的 **删除系统cron** 可将这两部分都还原。

如果您更愿意手动操作,只需两个步骤:

**禁用由访客触发的版本。** 使用 **设置**,然后 **文件管理器**,在 `/* That's all, stop editing! */` 这一行之上,将以下内容添加到 `wp-config.php` 中:

```php
define( 'DISABLE_WP_CRON', true );
```

**添加真正的任务。** 在 **设置**,然后 **Cron** 中:

- 计划:`*/5 * * * *`
- 标签:`WordPress cron`
- 命令:`cd ~/htdocs/yourdomain.co.nz && /usr/bin/wp cron event run --due-now`

> **Warning:** 请勿跳过 `DISABLE_WP_CRON` 这一半。如果两者同时运行,每个计划任务都可能触发两次:重复的邮件、重复的订单处理、订阅类插件的重复扣款。请使用 WP-Cron 部分中的一键操作,这样就不会发生这种情况。

## WooCommerce 与后台队列

WooCommerce 使用后台队列来处理订单状态变更、订阅续订、邮件发送和库存更新。它依赖 WP-Cron,因此在访问量较少的商店中,这正是受影响最严重的工作负载。

一旦设置好真正的计划任务,该队列就会每五分钟处理一次。您可以在 wp-admin 的 **WooCommerce**,然后 **Status**,然后 **Scheduled Actions** 中查看其运行情况。

高流量商店可以改用 `*/2 * * * *`。低于该频率通常无济于事:您花在启动进程上的时间会比实际处理任务的时间还多。请参阅[设置 WooCommerce](https://support.kapsulehost.com/zh-cn/wordpress-woocommerce)。

## 管理现有任务

任务列表显示 **Label**、**Schedule**、**Command**、**上次运行** 和 **Status**,每一行都有两个操作:

- **Disable** 会暂停某个任务而不删除它,并会变为 **Enable** 以便将其重新启用。当您想测试某个任务是否引发了问题时,可以使用此操作。
- **Delete** 会永久删除该任务。系统会要求您确认,确认后计划运行会立即停止。

> **Important:** 删除某个 Cron 任务后将无法撤销。该计划任务会立即从服务器上被移除。如果您只是想暂时停止它,请使用 **Disable**。

## 查找输出内容

KapsuleHost 创建的每个任务都会为您捕获其输出内容。标准输出和错误信息会被附加到您站点用户主目录下某个 `cron-logs` 目录中的日志文件中,每个任务对应一个文件。

该日志几乎能回答所有"我的任务运行了吗?"这类问题,因为它记录了该命令所打印的内容以及它所引发的任何错误。

要查看该日志,请通过 SSH 连接,并查看 `~/cron-logs/`。SSH 使用密钥验证,因此请先在该站点的 **设置**,然后 **SSH 密钥** 选项卡中添加您的公钥:请参阅[添加 SSH 密钥](https://support.kapsulehost.com/zh-cn/adding-ssh-keys)。

> **Note:** File Manager 和 SFTP 账户仅限于访问您的站点目录 `~/htdocs/yourdomain.co.nz`,而 `cron-logs` 则位于其上一级。这是有意为之的设计:它能使拥有 SFTP 访问权限的承包商无法访问网站之外的任何内容。请使用原生 SSH 来访问日志,或者按下文所示将输出重定向到您的站点目录中。

如果您希望将输出保存到 File Manager 能够打开的位置,可以自行重定向:

```
cd ~/htdocs/yourdomain.co.nz && /usr/bin/wp cron event run --due-now >> ~/htdocs/yourdomain.co.nz/wp-content/cron.log 2>&1
```

`2>&1` 会将错误信息发送到与常规输出相同的文件中。如果不加上它,错误信息将无处可寻。

> **Warning:** 您站点目录中的任何内容都有可能通过网络被请求访问。请将重定向的日志放在 `wp-content` 下,而不是放在站点根目录下,为其取一个没人能猜到的名称,并在调试完成后将其删除。

## 良好实践

- **错开您的计划时间。** 如果六个任务全部设置为 `0 2 * * *`,它们就会同时启动。请将它们分散开来:`0 2`、`10 2`、`20 2`。
- **除非确实需要,否则不要使用每分钟运行一次。** 对于几乎所有情况(包括 WordPress 和 WooCommerce),`*/5` 已经足够。
- **让任务保持简短。** 耗时超过其运行间隔的任务会与下一次运行发生重叠。
- **为任何产生大量输出的任务重定向输出**,以免某个"话多"的任务占满您的磁盘空间。
- **偶尔检查一下任务列表。** 已卸载插件遗留下来的任务会持续运行。

## 疑难排解

**任务似乎从未运行过。** 请先检查路径。打开日志文件。然后确认状态为 **Active** 而非 **Disabled**。接着通过 SSH 运行相同的命令,看看会出现什么结果。

**日志中出现"command not found"。** 这是因为缺少完整路径。请使用 `/usr/bin/php`、`/usr/bin/wp`、`/usr/bin/curl`,而不是单独的命令名称。

**权限被拒绝。** 该任务以您站点的系统用户身份运行。该用户需要拥有该命令所涉及的一切内容的所有权,或至少具备读取权限。请在[使用文件管理器](https://support.kapsulehost.com/zh-cn/file-manager)中检查权限设置。

**WordPress 任务仍然延迟运行。** 请确认替换操作的两个部分都已到位:**设置**,然后 **Cron** 中存在该计划任务,并且已设置 `DISABLE_WP_CRON`。**WordPress** 选项卡上的 **WP-Cron** 部分会显示这两者的当前状态。

**任务可以运行,但运行期间网站变得缓慢。** 请将其移至访问量较少的时段运行,或将任务拆分为更小的批次。站点层面的资源使用情况可在 **性能** 下查看:请参阅[提升网站速度](https://support.kapsulehost.com/zh-cn/website-speed)。

**插件更新后某个任务停止工作。** 命令路径可能已发生变化。请检查日志,然后通过删除旧任务并添加一个更正后的新任务来更新任务列表中的命令。
