Skip to content

About

simple-scheduler — A lightweight Rust task scheduler with a REST API. Supports cron expressions, second-level intervals and one-shot tasks, with JSON file config, hot reload, parallel execution (up to 64 tasks), process locks, log rotation and completion webhooks.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

简单调度器(simple-scheduler)

License

一个带有REST API控制的简单任务调度器。

特性

  • 基于文件的任务配置
  • 支持cron表达式
  • 进程锁防止多个实例同时运行
  • 变量替换功能(支持 ${tasksDir})
  • 任务配置热重载
  • API主机和端口配置(默认:127.0.0.1:18081)
  • 带有安全限制的命令执行端点

环境变量

变量 默认值 说明
SCHEDULER_API_HOST 127.0.0.1 API服务器绑定的主机IP(s)。支持多个IP,用逗号分隔。
SCHEDULER_API_PORT 18081 API服务器端口号
SCHEDULER_WORKER_THREADS 8 用于任务执行的工作线程数
SCHEDULER_MAX_TASKS 64 可以执行的最大任务数

API文档

POST /exec

在服务器上执行一个shell命令。

请求体:

{
    "cmd": "ls"
}

响应:

  • 200 OK - 命令成功执行
  • 403 Forbidden - 命令被限制(例如,危险命令如rm -rf /)
  • 408 请求超时 - 命令执行在30秒后超时
  • 500 内部服务器错误 - 命令执行因内部错误失败

示例请求:

curl -s -X POST http://localhost:18081/exec \
     -H "Content-Type: application/json" \
     -d '{"cmd":"ls"}' | jq

示例响应:

{
    "status": 0,
    "stdout": "file1.txt\nfile2.txt",
    "stderr": ""
}
  • "status": 0 表示成功,其它值表示失败。
  • 接口超时时间为30秒,如果有执行命令超过30秒的需求,请使用task调度,异步通知方案。

受限命令列表

为了安全起见,以下命令被完全禁止执行:

  • reboot
  • shutdown
  • rm -rf /
  • dd if=/dev/zero of=/dev/sda
  • mkfs.ext4 /dev/sda
  • mv /home /tmp
  • poweroff
  • halt
  • init 0
  • fdisk /dev/sda

此外,以下命令前缀也被限制(以防止潜在的危险操作):

  • rm (文件删除)
  • chmod (权限修改)
  • chown (所有者修改)

如果尝试执行这些命令,API 将返回 403 Forbidden 状态码。

安全考虑

该服务默认阻止潜在危险命令,包括:

  • 系统重启/关机命令(reboot、shutdown、poweroff等)
  • 文件系统破坏命令(rm -rf /、dd、mkfs.ext4等)
  • 潜在破坏性的磁盘操作
  • 权限修改命令(chmod、chown)

服务默认绑定到127.0.0.1以确保安全,不应在没有适当身份验证的情况下公开暴露。


🚀 特性

  • ⚡ 并行执行: 默认 8 个工作线程,最大支持 64 个并行任务
  • 🎯 多种调度模式: 支持一次性任务、cron 表达式和定时间隔
  • 🔄 动态配置: 监控配置文件变化,自动重载任务
  • 🔐 进程锁: 防止同一配置目录下多个实例同时运行
  • 💫 变量替换: 支持 ${tasksDir} 变量替换
  • 📄 日志管理: 自动日志轮转,支持自定义日志文件权限

🤖 功能设计需求说明

原生太的cron只支持分钟级,无法满足秒级需求。 因此简单任务调度器实现了秒级及cron的整合。

📋 核心需求

1. 配置文件目录结构

  • 配置目录: tasks 目录
  • 任务描述: 每个任务以一个 JSON 文件进行描述
  • 文件格式: 必须以 .spec.json 结尾

2. 任务描述规则

基础格式示例:

{
    "name": "关键数据备份任务",
    "interval": 60,
    "command": "/usr/bin/bash /opt/scripts/backup.sh",
  "log": "${tasksDir}/backup.sh.log",
  "error": "${tasksDir}/backup.sh.error.log"
}

完整格式支持:

{
    "name": "完整任务示例",
    "enabled": true,
    "interval": 60,
    "cron": "0 0 * * *",
    "once": false,
    "command": "/usr/bin/bash ${tasksDir}/scripts/task.sh",
  "log": "${tasksDir}/task.log",
  "error": "${tasksDir}/task.error.log",
    "notify_url": "http://localhost:3000/webhook"
}

3. Rust 实现要求

3.1 任务加载
  • ✅ 初始化时加载 tasks 目录下的所有 .spec.json 任务
  • ✅ 使用动态 JSON 解析,无需定义额外的 task 结构体
  • ✅ 支持递归扫描子目录
3.2 动态监控
  • ✅ 监控 tasks 目录文件变化
  • ✅ JSON 文件修改时自动重新加载
  • ✅ 支持热重载,无需重启进程
3.3 命令处理
  • ✅ 使用 shell-words 处理复杂长命令
  • ✅ 支持变量替换 (${tasksDir})
  • ✅ 安全的命令解析和执行
3.4 日志规范
  • ✅ 记录任务每个周期的开始时间
  • ✅ 记录 CPU、内存使用情况
  • ✅ 记录总执行时间
  • ✅ 日志输出到指定的 log 文件
  • ✅ 自动日志轮转(20MB)
3.5 错误处理
  • ✅ 错误日志写入对应的 error 文件
  • ✅ 异常处理不影响其他任务执行
  • ✅ 详细的错误信息记录
3.6 技术栈
  • ✅ 使用最新的 Rust 组件和依赖
  • ✅ 所有实现集中在 main.rs 中
  • ✅ 异步编程模型

🚀 性能优化

并行任务执行器

优化目标: 将串行任务执行器修改为并行任务执行器

调度算法:

下一个任务开始时间 = 任务间隔时间 - 任务执行时间

边界条件处理:

如果 任务间隔时间 < 任务执行时间:
    则 下一个任务开始时间 = 0 (立即执行)

实现特性:

  • ✅ 默认支持最多 64 个并行任务
  • ✅ 智能调度避免任务堆积
  • ✅ 独立线程池管理
  • ✅ 任务执行状态监控

📊 架构设计

┌─────────────────┐    ┌──────────────────┐    ┌─────────────────┐
│   配置监控器     │────│   任务调度器      │────│   执行器线程池   │
│  (File Watcher) │    │  (Task Scheduler) │    │ (Thread Pool)   │
└─────────────────┘    └──────────────────┘    └─────────────────┘
         │                        │                        │
         │ JSON 文件变化           │ 任务分发               │ 并行执行
         ▼                        ▼                        ▼
┌─────────────────┐    ┌──────────────────┐    ┌─────────────────┐
│   动态重载       │    │   智能调度        │    │   日志 & 监控    │
│ (Hot Reload)    │    │ (Smart Schedule)  │    │ (Log & Monitor) │
└─────────────────┘    └──────────────────┘    └─────────────────┘

📋 系统要求

组件 版本 描述
操作系统 Linux 支持所有主流发行版
Rust 1.70+ 编译时必需
内存 128MB+ 推荐配置

🔧 安装与构建

📦 快速开始

# 克隆项目
git clone <repository-url>
cd simple-scheduler

# 构建发布版本
cargo build --release

# 或使用构建脚本生成多架构二进制文件
./build.sh

🏗️ 构建选项

命令 描述
cargo build --release 构建当前架构的优化版本
./build.sh 构建多架构二进制文件
cargo test 运行测试

📁 项目结构

simple-scheduler/
├── 🚀 simple-scheduler          # 可执行文件
└── 📂 tasks/                    # 任务配置目录
    ├── 📂 hello/
    │   ├── 📜 hello.js
    │   └── ⚙️ hello.spec.json  # 任务配置文件
    └── 📂 sysinfo/
        ├── 📜 sysinfo.sh
        └── ⚙️ sysinfo.spec.json

⚙️ 配置文件格式

任务配置文件必须以 .spec.json 结尾,格式如下:

{
  "name": "任务名称",
  "enabled": true,
  "command": "/usr/bin/bash ${tasksDir}/script.sh",
  "log": "${tasksDir}/task.log",
  "error": "${tasksDir}/task.error.log",
  "once": false,
  "cron": "0 0 * * *",
  "interval": 60,
  "notify_url": "http://localhost:3000/webhook"
}

📊 配置字段说明

字段 类型 必需 默认值 描述
name string ✅ - 任务名称(唯一标识)
enabled boolean ❌ true 是否启用任务
command string ✅ - 要执行的命令
log string ✅ - 标准输出日志文件路径
error string ✅ - 错误日志文件路径
once boolean ❌ false 是否只执行一次
cron string ❌ - Cron 表达式(支持标准 5 字段格式)
interval number ❌ 60 执行间隔(秒)
notify_url string ❌ - 任务完成后的通知 URL

🔄 调度优先级

任务调度按以下优先级执行:

once > cron > interval

📋 示例说明

📖 点击查看详细示例

1. 一次性任务

{
  "once": true,
  "cron": "0 0 * * *",
  "interval": 60
}

⚡ 执行一次后退出,忽略 cron 和 interval

2. Cron 调度

{
  "once": false,
  "cron": "0 0 * * *",
  "interval": 60
}

⏰ 每天 0 点执行一次,忽略 interval

3. 间隔调度

{
  "once": false,
  "cron": "",
  "interval": 3
}

🔄 每 3 秒执行一次


🚦 使用方法

🎯 基本用法

# 使用默认配置目录 ./tasks
./simple-scheduler

# 指定配置目录
./simple-scheduler --tasks-dir /path/to/tasks

# 查看版本
./simple-scheduler --version

# 查看帮助
./simple-scheduler --help

# 使用systemd方案启动(默认)
./simple-scheduler/install.sh

# 使用pm2方案启动
pm2 start /opt/simple-scheduler/simple-scheduler-$(uname -m) --name "simple-scheduler"
pm2 save

🌍 环境变量配置

# 设置工作线程数和最大任务数
export SCHEDULER_WORKER_THREADS=4
export SCHEDULER_MAX_TASKS=16

# 运行调度器
./simple-scheduler --tasks-dir $(pwd)/tasks

💫 变量替换

在 command、log、error 字段中都可以使用 ${tasksDir} 变量:

{
  "command": "/usr/bin/node ${tasksDir}/scripts/app.js",
  "log": "${tasksDir}/app.log",
  "error": "${tasksDir}/app.error.log"
}

💡 字段替换规则:

  • command 中的 ${tasksDir} 会替换为任务根目录(--tasks-dir 对应目录)的绝对路径。
  • log / error 中的 ${tasksDir} 会替换为当前任务 *.spec.json 所在目录的绝对路径。

📝 日志功能

📋 功能特性

  • 🔄 自动轮转: 当日志文件超过 20MB 时自动清空
  • 🔐 权限管理: 自动设置日志文件权限为 777,支持多用户访问
  • 📊 详细记录: 包含任务开始时间、执行时长、输出内容等信息

📄 日志格式示例

2025-07-03 15:44:11 - Started at 2025-07-03 15:44:11, Total Time: 0.05s
Task output content here...

🔒 进程锁机制

每个 tasks 目录对应一个进程锁,防止多个实例同时管理相同的任务集:

# 实例 1 - 成功启动
./simple-scheduler --tasks-dir /opt/tasks
# ✅ 成功启动

# 实例 2 - 启动失败
./simple-scheduler --tasks-dir /opt/tasks
# ❌ 输出: Error: Another simple-scheduler instance is already running for tasks directory '/opt/tasks'

💡 锁文件存储在 /tmp/simple-scheduler-*.lock


🔔 通知功能

当 once: true 的任务执行完成后,会向 notify_url 发送 POST 请求:

curl -X POST \
  -H "Content-Type: application/json" \
  -d '{"name":"任务名称","command":"...","..."}' \
  http://localhost:3000/webhook

🛠️ 故障排除

⚠️ 常见问题

🔐 权限被拒绝错误
  • 检查日志文件权限
  • 确保进程有写入日志目录的权限

解决方案:

# 检查日志目录权限
ls -la /tmp/

# 修改权限
chmod 777 /tmp/your-log-directory
⏸️ 任务不执行
  • 检查 enabled 字段是否为 true
  • 验证 cron 表达式格式
  • 查看错误日志文件

检查清单:

  • 配置文件格式正确
  • 任务已启用
  • 命令路径正确
  • 日志文件路径可写
⚡ 多实例冲突
  • 确保不同的 tasks 目录
  • 检查 /tmp/simple-scheduler-*.lock 文件

解决方案:

# 查看现有锁文件
ls -la /tmp/simple-scheduler-*.lock

# 清理无效锁文件(确保进程已退出)
rm /tmp/simple-scheduler-*.lock

About

simple-scheduler — A lightweight Rust task scheduler with a REST API. Supports cron expressions, second-level intervals and one-shot tasks, with JSON file config, hot reload, parallel execution (up to 64 tasks), process locks, log rotation and completion webhooks.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages