计划任务
计划任务功能基于 Cron 表达式,支持定时执行 Shell 命令或发送 HTTP 请求,用于自动化运维操作。
技术原理
任务调度机制
计划任务基于 Cron 调度器实现,其工作流程如下:
┌─────────────────────────────────────────────┐
│ Cron 调度器 │
│ │
│ 每分钟检查 → 匹配 Cron 表达式 → 触发任务 │
└──────────────────┬──────────────────────────┘
│
┌──────────┴──────────┐
▼ ▼
Shell 命令执行 HTTP 请求发送
(子进程 + 超时控制) (HTTP Client + 超时控制)
│ │
▼ ▼
记录执行结果 记录响应结果
(stdout/stderr) (状态码/响应体)- 调度精度:最小粒度为 1 分钟(标准 5 字段 Cron)
- 并发执行:多个任务可同时触发,互不阻塞
- 超时保护:每个任务均支持独立超时设置,防止任务挂起
- 持久化:任务配置和执行历史均存储在 SQLite 数据库中
Cron 表达式说明
Cron 表达式由 5 个字段组成(分 时 日 月 周):
┌───────────── 分钟 (0-59)
│ ┌───────────── 小时 (0-23)
│ │ ┌───────────── 日 (1-31)
│ │ │ ┌───────────── 月 (1-12)
│ │ │ │ ┌───────────── 星期 (0-6,0=周日)
│ │ │ │ │
* * * * *特殊字符说明
| 字符 | 含义 | 示例 |
|---|---|---|
* | 任意值 | * * * * * 每分钟 |
, | 枚举多个值 | 0 8,12,18 * * * 每天 8、12、18 点 |
- | 范围 | 0 8-18 * * * 8 点到 18 点每小时 |
/ | 步长 | */5 * * * * 每 5 分钟 |
常用示例
| 表达式 | 说明 |
|---|---|
* * * * * | 每分钟执行一次 |
0 * * * * | 每小时整点执行 |
0 2 * * * | 每天凌晨 2 点执行 |
0 2 * * 0 | 每周日凌晨 2 点执行 |
0 2 1 * * | 每月 1 日凌晨 2 点执行 |
*/5 * * * * | 每 5 分钟执行一次 |
0 8-18 * * 1-5 | 工作日 8:00-18:00 每小时执行 |
0 0 1,15 * * | 每月 1 日和 15 日零点执行 |
30 23 * * 5 | 每周五 23:30 执行 |
配置说明
进入 计划任务 页面,点击 新建 按钮:
基础配置
| 字段 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
| 名称 | 字符串 | ✅ | — | 任务名称 |
| 启用 | 布尔 | ✅ | true | 是否启用 |
| Cron 表达式 | 字符串 | ✅ | — | 执行时间规则 |
| 任务类型 | 枚举 | ✅ | Shell | Shell 命令 或 HTTP 请求 |
Shell 命令配置
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| 命令 | 字符串 | ✅ | 要执行的 Shell 命令 |
| 超时时间 | 整数 | ❌ | 命令执行超时(秒),0 表示不限制 |
HTTP 请求配置
| 字段 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
| URL | 字符串 | ✅ | — | 请求地址 |
| 方法 | 枚举 | ❌ | GET | GET 或 POST |
| 请求头 | 文本 | ❌ | — | 自定义请求头,格式:Key: Value |
| 请求体 | 文本 | ❌ | — | POST 请求体内容 |
| 超时时间 | 整数 | ❌ | 30 | 请求超时(秒) |
常见任务模板
模板 1:数据库备份
每天凌晨 3 点备份 SQLite 数据库,保留最近 7 天:
bash
# 备份并清理旧备份
cp /var/lib/netpanel/netpanel.db /backup/netpanel-$(date +%Y%m%d).db
find /backup -name "netpanel-*.db" -mtime +7 -delete| 字段 | 值 |
|---|---|
| 名称 | 每日数据库备份 |
| Cron 表达式 | 0 3 * * * |
| 任务类型 | Shell 命令 |
| 超时时间 | 60 秒 |
模板 2:日志清理
每周日凌晨 4 点清理 30 天前的日志文件:
bash
find /var/log/netpanel -name "*.log" -mtime +30 -delete
echo "日志清理完成: $(date)"| 字段 | 值 |
|---|---|
| 名称 | 清理旧日志 |
| Cron 表达式 | 0 4 * * 0 |
| 任务类型 | Shell 命令 |
模板 3:证书续期检查
每天检查 SSL 证书是否即将到期(30 天内),并发送通知:
bash
# 检查证书有效期
CERT_FILE="/etc/ssl/certs/example.com.crt"
EXPIRE_DATE=$(openssl x509 -enddate -noout -in "$CERT_FILE" | cut -d= -f2)
EXPIRE_EPOCH=$(date -d "$EXPIRE_DATE" +%s)
NOW_EPOCH=$(date +%s)
DAYS_LEFT=$(( (EXPIRE_EPOCH - NOW_EPOCH) / 86400 ))
if [ "$DAYS_LEFT" -lt 30 ]; then
echo "警告:证书将在 ${DAYS_LEFT} 天后过期!"
exit 1
fi
echo "证书有效,剩余 ${DAYS_LEFT} 天"| 字段 | 值 |
|---|---|
| 名称 | 证书续期检查 |
| Cron 表达式 | 0 9 * * * |
| 任务类型 | Shell 命令 |
模板 4:服务健康检查
每 5 分钟检查一次内网服务是否正常响应:
| 字段 | 值 |
|---|---|
| 名称 | 服务健康检查 |
| Cron 表达式 | */5 * * * * |
| 任务类型 | HTTP 请求 |
| URL | http://127.0.0.1:3000/health |
| 方法 | GET |
| 超时时间 | 10 秒 |
模板 5:定时发送 WebHook 通知
每天早上 8 点发送每日状态报告到钉钉/企业微信:
| 字段 | 值 |
|---|---|
| 名称 | 每日状态报告 |
| Cron 表达式 | 0 8 * * 1-5 |
| 任务类型 | HTTP 请求 |
| URL | https://oapi.dingtalk.com/robot/send?access_token=xxx |
| 方法 | POST |
| 请求头 | Content-Type: application/json |
| 请求体 | {"msgtype":"text","text":{"content":"NetPanel 运行正常,今日报告已生成"}} |
查看执行历史与日志
在任务列表中,点击任务右侧的 历史 按钮,可查看执行记录。
日志字段说明
| 字段 | 说明 |
|---|---|
| 执行时间 | 任务实际触发的时间戳 |
| 执行结果 | 成功 / 失败 / 超时 |
| 退出码 | Shell 命令的退出状态码(0 表示成功) |
| 耗时 | 任务执行总耗时(毫秒) |
| 输出内容 | Shell 的 stdout/stderr 或 HTTP 响应体(截取前 4KB) |
结果状态说明
| 状态 | 含义 |
|---|---|
| ✅ 成功 | Shell 退出码为 0,或 HTTP 状态码为 2xx |
| ❌ 失败 | Shell 退出码非 0,或 HTTP 状态码为 4xx/5xx |
| ⏱ 超时 | 执行时间超过设定的超时时间 |
常见问题排查
任务未按时执行
- 检查任务是否已启用(列表中开关是否打开)
- 验证 Cron 表达式是否正确(可使用 crontab.guru 在线验证)
- 检查服务器时区是否正确:
date命令查看当前时间 - 查看系统日志确认调度器是否正常运行
Shell 命令执行失败
- 检查命令语法:在终端手动执行命令,确认无语法错误
- 检查执行权限:NetPanel 进程用户是否有权限执行该命令
- 检查路径问题:使用绝对路径,避免依赖
$PATH环境变量 - 查看错误输出:在执行历史中查看 stderr 输出内容
bash
# 推荐:使用绝对路径
/usr/bin/cp /data/netpanel.db /backup/netpanel-$(date +%Y%m%d).db
# 不推荐:依赖 PATH
cp /data/netpanel.db /backup/netpanel-$(date +%Y%m%d).dbHTTP 请求失败
- 检查 URL 是否可访问:在服务器上用
curl手动测试 - 检查超时设置:如果目标服务响应慢,适当增大超时时间
- 检查请求头格式:每行一个
Key: Value,注意冒号后有空格 - 查看响应内容:在执行历史中查看 HTTP 响应体
最佳实践
避免任务重叠
如果任务执行时间可能超过调度间隔,建议使用文件锁防止重叠执行:
bash
# 使用 flock 防止任务重叠
flock -n /tmp/backup.lock /usr/bin/backup.sh || echo "上一次任务仍在执行,跳过本次"设置合理的超时时间
- 数据库备份:建议 60-300 秒
- HTTP 健康检查:建议 10-30 秒
- 日志清理:建议 120 秒
- 避免设置为 0(不限制),防止任务挂起占用资源
配置失败通知
结合 回调系统 或在 Shell 命令中加入失败通知逻辑:
bash
#!/bin/bash
if ! /usr/bin/backup.sh; then
curl -X POST "https://oapi.dingtalk.com/robot/send?access_token=xxx" \
-H "Content-Type: application/json" \
-d '{"msgtype":"text","text":{"content":"⚠️ 备份任务失败,请检查!"}}'
exit 1
fiShell 命令安全
Shell 命令以 NetPanel 进程的权限执行。请确保命令来源可信,避免执行危险操作(如 rm -rf /)。建议将复杂逻辑封装为独立脚本文件,并设置适当的文件权限。
时区设置
Cron 表达式基于服务器本地时区。如果时区不正确,可以通过环境变量设置:
bash
# Docker 部署时设置时区
docker run -e TZ=Asia/Shanghai ...
# 系统设置时区
timedatectl set-timezone Asia/Shanghai