Skip to content

SimpleScheduler 是一个基于配置文件驱动的轻量级服务调度器。它的核心设计理念是将 服务执行的细节(如 API 地址、命令行工具)与客户端调用分离。客户端只需关心业务参数,而无需了解后端的具体实现。

License

Notifications You must be signed in to change notification settings

ShouChenICU/SimpleScheduler

Repository files navigation

🚀 SimpleScheduler

GitHub License Node.js Version Framework

SimpleScheduler 是一个基于配置文件驱动的轻量级服务调度器。它的核心设计理念是将 服务执行的细节(如 API 地址、命令行工具)与客户端调用分离。客户端只需关心业务参数,而无需了解后端的具体实现。

这种模式使得服务配置更加集中、安全,并且易于管理和扩展,尤其适合需要统一管理多种异构任务(如 API 调用、脚本执行)的场景。

🎯 核心理念

在传统架构中,客户端通常直接调用特定的 API 地址或执行命令。当服务地址、参数或实现方式变更时,往往需要修改客户端代码。

SimpleScheduler 通过引入一个 服务配置层 来解决这个问题:

  1. 🧑‍💼 管理员config/services.json 中定义一系列服务,每个服务包含固定的执行配置(如 URL、命令、参数映射关系)。
  2. 💻 客户端 只需提供 serviceId 和业务相关的 payload(如 city, userId)。
  3. ⚙️ 调度器 根据 serviceId 查找服务配置,验证并映射客户端传入的参数,然后执行任务(调用 API 或运行本地命令)。

Note

这种方式将 “做什么”(客户端业务请求)与 “怎么做”(服务端具体实现)完全解耦。

✨ 主要特性

  • 📄 配置驱动:所有可执行服务均在 services.json 中定义,无需修改代码即可增删服务。
  • 🛠️ 多任务类型:原生支持 WEB_SERVICE(调用 HTTP/S API)和 LOCAL_TOOL(执行本地命令行工具)。
  • 🔗 参数映射:强大的参数映射功能,可将客户端的业务参数灵活映射到 URL 路径、查询参数、请求体、命令行参数或环境变量。
  • 🛡️ 安全隔离
    • 服务白名单机制,只有预定义的服务才能执行。
    • 禁用 shell 模式执行命令,防止命令注入。
    • 客户端无法指定执行的 URL 或命令,只能传递业务参数。
  • 💾 持久化存储:所有任务状态和执行结果都通过 unstorage 持久化到本地文件系统(.data/ 目录)。
  • 🚦 并发控制:通过多队列机制(config/queues.json)管理不同优先级任务的并发数。
  • 📡 实时事件流:客户端可通过 SSE (Server-Sent Events) 实时获取任务的状态更新、日志和最终结果。

🏗️ 架构概览

SimpleScheduler 基于 Nitro 框架构建,其核心服务均为单例模式,在应用启动时自动初始化。

  • ConfigManager: 加载并验证 services.jsonqueues.json 配置文件。
  • StorageService: 负责任务和结果的持久化存储。
  • JobManager: 管理任务的生命周期(创建、状态变更、事件通知)。
  • QueueManager: 基于并发配置调度任务队列。
  • TaskExecutor: 根据服务类型(WEB_SERVICELOCAL_TOOL)执行具体任务。
  • CleanupService: 定期清理过期的任务和资源。

🚀 快速开始

✅ 环境要求

  • Node.js >= 18.0.0
  • Yarn

🛠️ 安装与运行

  1. 克隆仓库

    git clone https://github.com/ShouChenICU/SimpleScheduler.git
    cd simplescheduler
  2. 安装依赖

    yarn install
  3. 启动开发服务器

    yarn dev

    [!IMPORTANT] 服务将运行在 http://localhost:3005

🔌 API 使用

1. 调度一个任务

通过 POST /api/v1/schedule 发起一个新任务。

请求体:

{
  "serviceId": "weather-api",
  "payload": {
    "city": "Beijing"
  },
  "queue": "default"
}
  • serviceId: 对应 config/services.json 中定义的服务 ID。
  • payload: 业务参数,必须符合服务定义中的 parameters 约束。
  • queue (可选): 指定任务队列,默认为 default

成功响应:

{
  "jobId": "a1b2c3d4-e5f6-7890-1234-567890abcdef"
}

2. 实时获取任务状态和结果

通过 GET /api/v1/stream/{jobId} 订阅任务的 Server-Sent Events。

curl -N http://localhost:3005/api/v1/stream/a1b2c3d4-e5f6-7890-1234-567890abcdef

事件流示例:

event: status_update
data: {"status":"RUNNING"}

event: log
data: {"message":"Executing web service request to https://api.openweathermap.org/data/2.5/weather"}

event: result
data: {"weather":{"main":"Clear","description":"clear sky"},"main":{"temp":20,"feels_like":19.5}}

event: status_update
data: {"status":"COMPLETED"}

3. 查询任务最终状态

如果不想使用 SSE,也可以通过 GET /api/v1/status/{jobId} 查询任务的最终状态和结果。

⚙️ 服务配置

所有服务都在 config/services.json 中定义。下面是一个 WEB_SERVICE 和一个 LOCAL_TOOL 的示例。

Caution

服务配置是系统的核心,不正确的配置可能导致任务执行失败或产生安全风险。

Web 服务示例

此服务用于查询天气,客户端只需提供 cityapiKey 从服务端配置中自动附加。

{
  "id": "weather-api",
  "type": "WEB_SERVICE",
  "description": "查询城市天气信息",
  "parameters": {
    "city": { "type": "string", "required": true }
  },
  "config": {
    "url": "https://api.openweathermap.org/data/2.5/weather",
    "method": "GET",
    "paramMapping": {
      "query": {
        "city": "q",
        "apiKey": "appid"
      }
    }
  },
  "output": "JSON"
}

本地工具示例

此服务用于执行一个备份脚本,客户端提供 database 名称。

{
  "id": "database-backup",
  "type": "LOCAL_TOOL",
  "description": "执行数据库备份",
  "parameters": {
    "database": { "type": "string", "required": true }
  },
  "config": {
    "command": "/usr/local/bin/backup-tool",
    "args": ["--format", "sql"],
    "paramMapping": {
      "args": {
        "database": 0
      }
    }
  },
  "output": "TEXT"
}
  • paramMapping.args: 将客户端的 database 参数插入到 args 数组的第 0 个位置。

文件输出配置

output 类型为 FILE 时,SimpleScheduler 支持两种方式获取二进制数据:

方式 1:从标准输出获取(推荐用于直接输出二进制数据的工具)

{
  "id": "file-output-from-stdout",
  "type": "LOCAL_TOOL",
  "description": "从标准输出获取二进制数据",
  "parameters": {
    "content": { "type": "string", "required": true }
  },
  "config": {
    "command": "/bin/echo",
    "args": ["-n"],
    "paramMapping": {
      "args": { "content": 0 }
    }
  },
  "output": "FILE"
}

特点

  • 🚀 直接从 stdout 读取二进制数据
  • 📊 不打印日志,避免二进制内容乱码
  • 💾 数据直接保存为资源文件

方式 2:通过文件读取(推荐用于写入文件的工具)

{
  "id": "image-resize",
  "type": "LOCAL_TOOL",
  "description": "调整图片大小",
  "parameters": {
    "inputFile": { "type": "string", "required": true },
    "width": { "type": "number", "required": true },
    "height": { "type": "number", "required": true }
  },
  "config": {
    "command": "/usr/bin/convert",
    "args": ["-resize"],
    "cwd": "/tmp",
    "paramMapping": {
      "args": {
        "inputFile": 0,
        "width": 1,
        "height": 2
      },
      "outputFile": 3
    }
  },
  "output": "FILE"
}

工作流程

  1. 🎲 系统自动生成随机文件名(如 output_1699999999999_abc123.tmp
  2. 📝 将完整路径插入到 paramMapping.outputFile 指定的参数位置(位置 3)
  3. ⚙️ 执行命令:/usr/bin/convert -resize input.jpg 800 600 /tmp/output_xxx.tmp
  4. 📖 命令完成后读取该文件内容
  5. 🗑️ 自动删除临时文件
  6. 💾 将内容保存为资源

特点

  • ✅ 适用于需要指定输出文件的工具(ImageMagick、FFmpeg、tar 等)
  • 🔒 自动生成唯一文件名,避免并发冲突
  • 🧹 自动清理临时文件
  • 📝 可以打印命令的进度日志(stdout)

参数映射详解

paramMapping 支持多种映射方式,适用于不同场景:

Web 服务参数映射

"paramMapping": {
  "query": { "city": "q", "apiKey": "appid" },     // URL 查询参数
  "path": { "userId": "id" },                       // URL 路径参数 /user/{id}
  "body": { "email": "user_email" }                 // 请求体参数
}

本地工具参数映射

"paramMapping": {
  "args": { "database": 0, "format": 1 },          // 命令行参数位置
  "env": { "apiKey": "API_KEY" },                   // 环境变量
  "outputFile": 2                                   // 输出文件参数位置(仅用于 FILE 类型)
}

输出类型说明

  • TEXT: 文本输出,从 stdout 读取并保存为字符串
  • JSON: JSON 输出,尝试解析 stdout 为 JSON 对象
  • FILE: 二进制文件输出,根据 paramMapping.outputFile 配置决定获取方式:
    • 未配置:从 stdout 获取二进制数据(不打印日志)
    • 已配置:从生成的临时文件读取内容(可打印日志)

👨‍💻 开发

🧪 运行测试

项目包含一个简单的测试脚本,用于验证核心功能。

node test.mjs

📦 构建生产版本

yarn build
yarn preview

🤝 贡献

欢迎提交 Pull Request 或 Issue 来改进项目!

📄 许可证

本项目基于 MIT License 开源。

About

SimpleScheduler 是一个基于配置文件驱动的轻量级服务调度器。它的核心设计理念是将 服务执行的细节(如 API 地址、命令行工具)与客户端调用分离。客户端只需关心业务参数,而无需了解后端的具体实现。

Topics

Resources

License

Stars

Watchers

Forks