Docs/ 运维/ 定时任务

定时任务

按计划运行命令或 HTTP 请求。创建第一个任务前请阅读“命令在哪里运行”:定时任务不在应用正在运行的容器中执行,而是在一个获得相同变量的一次性容器中执行。

创建定时任务

定时任务在控制台的 Cron Jobs 页面管理,也可以使用 sh0 cron。任务通常关联到一个应用。

  1. 在侧边栏打开 Cron Jobs,点击 Create Cron Job。
  2. Name -- 名称,例如 nightly-report。
  3. Application -- 任务所属的应用。不选应用时,只接受 HTTP 命令(见下文)。
  4. Schedule -- 5 字段 cron 表达式,按 UTC 计算。
  5. Command -- HTTP 请求(curl、wget 或单独的 URL),或在容器中运行的程序。
  6. 可选:Container Image(留空 = 应用的镜像)和 Timeout (seconds),默认 300。然后创建任务。

用 CLI 完成同样的操作(以下命令在服务器上实际执行过):

Terminal
$ sh0 cron create --app my-api --name nightly-report \
    --schedule "0 3 * * *" \
    --command "curl -s -X POST https://api.example.com/internal/report"
Cron job 'nightly-report' created (id: 72173a56-1962-47dc-88e5-2a276ef3bfcc)

$ sh0 cron trigger 72173a56-1962-47dc-88e5-2a276ef3bfcc
Cron job 'nightly-report' triggered.

$ sh0 cron runs 72173a56-1962-47dc-88e5-2a276ef3bfcc
RUN ID                                STATUS      EXIT    DURATION    STARTED
----------------------------------------------------------------------------------------------------
9e329bc7-01c5-41ec-9eb5-5ab745fde533  success     0       295ms       2026-10-02 02:33:23

命令在哪里运行

sh0 根据命令和任务设置,按以下顺序选择执行方式:

  • HTTP 请求 -- 以 curl 或 wget 开头的命令,或单独的 URL,不经 shell 执行:sh0 从服务器自行发送请求,限时 30 秒。支持 -X、-H 和 -d。响应状态码为 400 或以上时,本次运行记为失败。对于绑定到应用的任务,其项目的内部名称(my-api.internal,或单独的 my-api)会解析到对应服务。
  • 应用镜像 -- 其他命令在一个从应用当前镜像启动的全新一次性容器中运行,使用非 root 用户,接入 sh0 网络及其项目网络。它不是你正在运行的容器:应用运行时写入的文件不在其中,运行结束后容器即被删除。
  • 指定镜像 -- 如果填写了 Container Image,临时容器改用该镜像启动。
  • 既无应用也无镜像 -- 非 HTTP 命令在执行时被拒绝。sh0 从不在主机上运行定时命令。
Note
自 1.10.3 起:容器会获得应用的变量。绑定到应用的任务会获得应用及其项目的运行时变量(应用的值优先),与应用自身的容器完全相同。构建时变量不会传入。任务的输出会保存在运行历史中:打印出密钥的命令会把它留在那里,拥有该应用开发者权限的人都能看到。

在一个 Node.js 应用上实测:应用设置了 GREETING,其项目设置了 REGION。任务 env 会同时打印这两个变量,以及镜像内置的变量。

env -- app image (Node.js 22)
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOSTNAME=0.0.0.0
REGION=eu431
GREETING=hello431
NODE_VERSION=22.23.3
YARN_VERSION=1.22.22
PORT=3000
HOME=/home/node

GREETING 和 REGION 都在其中。HOME=/home/node 这一行表明使用的是非 root 用户。

命令规则

命令是单个程序加上它的参数。sh0 在创建任务时进行检查:

  • 没有 shell。字符 ; | & > <、反引号、$( 和换行都会被拒绝。不支持管道、&& 串联和变量展开。
  • 引号只在 HTTP 请求中生效。在容器中,命令按空格拆分:sh -c "echo hi" 不会像 shell 那样执行。HTTP 请求会正确处理引号,因此 -H "Authorization: Bearer …" 可以使用。
  • 重定向会被删除而不是被拒绝:> /dev/null、2>/dev/null、&> /dev/null 和 2>&1 在检查前被移除,因此从 crontab 复制的命令行可以直接使用。
  • 最多 4096 个字符。
Terminal
$ sh0 cron create --app my-api --name cleanup --schedule "0 3 * * *" --command "env | grep X"
Error: Invalid command: Command contains forbidden character '|'. Use simple commands without shell operators. (VALIDATION_ERROR)

需要数据库或机密的任务

绑定到应用的任务能看到应用的变量并解析其项目的内部名称,因此像 python manage.py cleanup 这样的命令会读取相同的 DATABASE_URL 并访问相同的 db.internal。如果工作应在正在运行的应用内完成,还有两种方式:

  • HTTP 端点。把任务暴露为应用的一个路由,用令牌保护,让定时任务通过内部名称调用它。工作在正在运行的应用内执行,使用其数据库连接和密钥。
  • 或在应用内部调度,使用框架自带的调度器(例如 Celery beat、node-cron 或 Laravel 调度器),适用于任务完全不应通过 HTTP 访问的情况。
Command
curl -s -X POST -H "Authorization: Bearer <token>" http://my-api.internal:3000/internal/cleanup
Note
sh0 从服务器发送请求,并仅在任务所属项目中正在运行的服务里解析 my-api.internal(或 my-api)。找不到对应运行中服务的名称会以明确的消息失败;不属于任何项目或运行在远程节点上的应用,必须通过其公共 URL 调用。令牌以明文写在任务命令中,任何能查看该任务的人都能看到:不要把它用于其他用途。

Cron 表达式语法

sh0 使用标准的 5 字段 cron 表达式,每个字段代表一个时间单位:

Cron expression format
┌───────────── minute (0-59)
│ ┌───────────── hour (0-23)
│ │ ┌───────────── day of month (1-31)
│ │ │ ┌───────────── month (1-12)
│ │ │ │ ┌───────────── day of week (0-6, Sunday = 0)
│ │ │ │ │
* * * * *
符号含义示例
*所有值* * * * * = 每分钟
,值列表0 8,12,18 * * * = 上午 8 点、中午、下午 6 点
-范围0 9-17 * * * = 上午 9 点到下午 5 点每小时
/步长*/15 * * * * = 每 15 分钟

常见模式

Frequently used cron schedules
# Every minute
* * * * *

# Every 5 minutes
*/5 * * * *

# Every hour at minute 0
0 * * * *

# Every day at midnight
0 0 * * *

# Every day at 3:30 AM
30 3 * * *

# Every Monday at 9:00 AM
0 9 * * 1

# First day of every month at midnight
0 0 1 * *

# Every weekday (Mon-Fri) at 6:00 AM
0 6 * * 1-5
Note
计划按 UTC 计算,与服务器时区无关。0 3 * * * 在 UTC 03:00 运行。调度器每 60 秒检查一次到期任务,因此执行最多可能比预定时间晚一分钟开始。

执行历史与日志

每次执行都会记录状态(success、failed 或 timeout)、退出码、耗时、开始和结束时间以及输出。在控制台中,打开任务的 Execution History,然后点击某次执行的 View output。使用 CLI:sh0 cron runs <id>。

Note
sh0 为每个任务保留最近 100 次执行,更早的记录会被删除。标准输出和错误输出各最多保留 64 KB。

启用和禁用任务

  • Disable 停止计划执行,但不删除任务及其历史;Enable 恢复执行。
  • Trigger Now(或 sh0 cron trigger <id>)立即执行一次,不受计划限制。
  • 删除任务(sh0 cron delete <id>)会同时删除其执行历史。

超时、重叠与限制

  • 超时 -- 默认 300 秒(CLI 中为 --timeout)。超时的执行记为 timeout 状态,并附带消息 “Job timed out after Ns”。
  • 重叠 -- 某个任务的一次执行尚未结束时,调度器不会再启动新的执行。被跳过的那一次不会记录在历史中。
  • 每个应用最多 50 个任务。
  • 没有重试,也没有失败通知。失败的执行不会重试,也不会发送告警:请查看执行历史,或让任务调用的端点自行报告失败。