# molens **Repository Path**: reginx/molens ## Basic Information - **Project Name**: molens - **Description**: 分布式一主多从任务调度服务,基于 Golang 1.25 + hashicorp/raft 构建。 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: main - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-07-31 - **Last Updated**: 2026-09-08 ## Categories & Tags **Categories**: Uncategorized **Tags**: 定时器, timer, 分布式, 高可用 ## README # Molens 分布式一主多从任务调度服务,基于 Golang + hashicorp/raft 构建。 - **可靠调度**:分层时间轮 + Raft 共识,支持延迟/周期任务,秒级故障接管 - **业务 ACK**:回调执行后异步确认,确保 `At-Least-Once` 语义 - **多语言 SDK**:Go / Java (JDK 17+) / Java (JDK 8+),零外部依赖,开箱即用 - **内置 Web UI**:任务管理、执行历史、集群监控一站式操作 --- ## 术语 | 术语 | 含义 | |------|------| | **集群节点** | 运行 molens 二进制,参与 Raft 共识的进程 | | **Leader** | 集群唯一主节点,负责接收任务、驱动时间轮、派发任务、清理过期数据 | | **Worker** | 执行任务回调的节点。Leader 派发后,目标节点执行 HTTP 回调 | | **调用方 (Client)** | 向 Molens 提交任务的 HTTP 调用者,通过 SDK 或直接 HTTP 调用 | | **回调方** | 接收任务执行 HTTP 回调的业务服务 | | **场景 (Scene)** | 任务上的透传标签(默认 `default`),随回调 `X-Scene` 头透传,无独立配置/授权能力 | | **ACK 任务** | Molens 内部为业务 ACK 创建的延迟确认任务,对用户透明 | ## 核心特性 | 特性 | 说明 | |------|------| | **分层时间轮** | 250ms tick,L0-L3 四层级覆盖 250ms ~ 4.2 年,`tick_interval_ms` 可配 | | **时间轮分布可视化** | 内置热力图 PNG 接口,直观展示任务在各槽位分布是否均匀、切主 rebuild 是否正确 | | **Raft 共识** | 一主多从,Leader 调度 Follower 热备,秒级故障接管 | | **双可靠性** | `At-Most-Once`(Fire-and-Forget)/ `At-Least-Once`(ACK + 重试) | | **业务 ACK** | 回调成功后异步确认,失败自动重试 TTL 次,端到端可靠 | | **两级超时/重试** | 任务级 > 全局默认 | | **自动停用保护** | 周期任务回调 404 或连续失败达 `max_fails` 阈值自动停用,防止无效调用 | | **crontab 调度** | 周期任务支持 5/6 段 crontab 表达式(可选时区,内部统一 UTC),复用既有重试/停用机制 | | **执行历史有界保留** | 每任务保留最近 N 条执行历史(默认 200),写入时同事务裁剪,磁盘占用有界 | | **增量恢复** | 节点重启保留本地数据增量追平,Leader 退群后自动重加,集群整体停机自动自举恢复 | | **批量提交** | 任务/派发/ACK 三通道批量写入 Raft,消除串行瓶颈 | | **优雅退出** | HTTP/RPC → 调度器 → Raft → 存储,30s 超时,保留本地数据 | | **多语言 SDK** | Go / Java 17+ / Java 8+,自动 Leader 发现 + 指数退避重试 | ## 架构 ``` ┌─────────────┐ │ Web UI │ Vue 3 管理界面 └──────┬──────┘ │ HTTP ▼ Client ──HTTP/JSON──▶ Leader (FSM + TimeWheel + Dispatcher) │ │ ↕ Raft TCP │ │ ↕ gRPC │ Follower-1 Follower-2 ... │ (FSM 副本 / Worker) │ └──▶ 回调方 (HTTP callback / ACK callback) ``` | 组件 | 说明 | |------|------| | `cmd/molens` | 主程序入口 | | `internal/raftnode` | Raft 节点封装 | | `internal/fsm` | 状态机(tasks / pending / nodes),BoltDB + SQLite 持久化 | | `internal/timewheel` | 分层时间轮(L0-L3) | | `internal/scheduler` | 调度编排、派发、ACK 处理、超时监控、过期清理 | | `internal/api/http` | RESTful API + 静态前端资源 | | `internal/rpc` | 集群内部 gRPC 通信 | | `pkg/model` | 对外 API 模型 | ## 快速启动 ### 单节点 ```bash make build ./bin/molens -config configs/node.json ``` - HTTP API:`http://localhost:18081` - Web UI:`http://localhost:18081/ui/` ### 三节点集群 ```bash make docker ``` ### 命令行管理 ```bash # 状态查看 ./bin/molens -config configs/node.json status # 启动 / 停止 / 重启 ./bin/molens -config configs/node.json start ./bin/molens -config configs/node.json stop ./bin/molens -config configs/node.json restart ``` ## Web UI Molens 内嵌 Vue 3 管理界面,功能包括: - **仪表盘**:实时统计、集群状态、清理统计、磁盘占用 - **任务管理**:创建(延迟/周期/cron 表达式)、列表、详情、执行历史、暂停/恢复、删除 - **执行记录**:全局执行历史,按任务/结果/时间筛选 - **延迟统计**:URL 级别延迟分位数(P50/P90/P99)与历史趋势 - **时间轮分布**:热力图直观查看任务在时间轮槽位中的分布均匀性 - **集群管理**:全节点实时统计表格(QPS/派发/任务/资源),Leader 置顶排序 从节点 UI 会自动检测角色并跳转到主节点,集群无 Leader 时提示等待选举。 ## 内置测试端点 方便开发和调试,无需搭建外部回调服务: | 端点 | 说明 | |------|------| | `POST /api/v1/test/callback` | 延迟 100ms 返回 `{"ok": true}` | | `POST /api/v1/test/ack` | 延迟 100ms 返回 `{"ok": true}` | 创建任务时将 `callback_url` / `ack_url` 填入对应测试端点即可验证完整链路。 ## API 概览 ### 任务 | 方法 | 路径 | 说明 | |------|------|------| | `POST` | `/api/v1/tasks` | 创建任务 | | `GET` | `/api/v1/tasks` | 任务列表 | | `GET` | `/api/v1/tasks/{id}` | 任务详情 | | `DELETE` | `/api/v1/tasks/{id}` | 删除任务 | | `POST` | `/api/v1/tasks/{id}/pause` | 暂停任务 | | `POST` | `/api/v1/tasks/{id}/resume` | 恢复任务 | | `GET` | `/api/v1/tasks/{id}/executions` | 任务执行历史 | | `GET` | `/api/v1/executions` | 全局执行记录列表 | ### 集群 | 方法 | 路径 | 说明 | |------|------|------| | `GET` | `/api/v1/cluster/status` | 集群节点状态 | | `GET` | `/api/v1/cluster/leader` | 主节点信息 | | `GET` | `/api/v1/cluster/stats` | 全部节点实时统计(一次性聚合) | | `GET` | `/api/v1/stats` | 本节点实时统计(支持 `?node_id=` 跨节点) | | `GET` | `/api/v1/stats/urls` | URL 延迟统计 | | `GET` | `/api/v1/timewheel/distribution.png` | 时间轮任务分布热力图(`?level=&width=`) | ### 创建任务示例 ```bash # 延迟任务(5s 后执行一次) curl -X POST http://localhost:18081/api/v1/tasks \ -H "Content-Type: application/json" \ -d '{ "type": "delayed", "interval_ms": 5000, "callback_url": "http://localhost:18081/api/v1/test/callback" }' # 周期任务(每 30s 执行一次,带业务 ACK) curl -X POST http://localhost:18081/api/v1/tasks \ -H "Content-Type: application/json" \ -d '{ "type": "periodic", "interval_ms": 30000, "callback_url": "http://localhost:18081/api/v1/test/callback", "ack_url": "http://localhost:18081/api/v1/test/ack", "ack_delay_ms": 5000, "scene": "default" }' # cron 表达式周期任务(每天 02:00,按 Asia/Shanghai 时区) curl -X POST http://localhost:18081/api/v1/tasks \ -H "Content-Type: application/json" \ -d '{ "type": "periodic", "cron_expr": "0 2 * * *", "timezone": "Asia/Shanghai", "callback_url": "http://localhost:18081/api/v1/test/callback" }' ``` ## 回调与 ACK 协议 Molens 任务触发后,Leader 通过 Worker 节点向回调方发起 HTTP 请求。若配置了业务 ACK,回调方需主动确认执行结果,Molens 会在 ACK 超时后发起 ACK 回调验证。 ### 一次性任务(delayed)的回调与 ACK 概念 对一次性任务(`type: "delayed"`),执行结果由「回调(Callback)」和「确认(ACK)」两个阶段共同决定,两者职责不同: | 阶段 | 触发方 | 含义 | 返回 2xx 表示 | |------|--------|------|--------------| | **Callback** | Molens → `callback_url` | 任务触发通知,即「任务已投递」 | 业务方已**接收**该任务(不代表处理完成) | | **ACK** | Molens → `ack_url` | 二次确认,即「任务是否真正处理完成」 | 业务方已**处理完成** | **任务状态流转(带业务 ACK 的一次性任务):** ``` firing (已派发 callback) │ callback 返回 2xx(已接收) ▼ awaiting_ack (待确认) │ 延迟 ack_delay_ms 后,Molens 向 ack_url 探测 ▼ ├─ 2xx → done (处理完成) └─ 非 2xx → 按 TTL 重试,TTL 耗尽 → failed ``` 关键语义: - **Callback 是「通知」,ACK 是「确认」**:callback 返回 2xx 只代表业务方收到了任务,业务可能仍在异步处理中;最终成败以 ACK 探测结果为准。 - **只有 callback 成功(含重试后成功)才会进入 ACK 阶段**:callback 失败走 `max_retries` 重试,重试耗尽则任务直接 `failed`,不会创建 ACK 任务。 - **ACK 的方向是 Molens 主动探测业务方**(`Molens → ack_url`),而非业务方向 Molens 上报。业务方只需暴露一个幂等的 `ack_url` 端点,根据 `X-Fire-ID` 返回处理结果即可,接入成本低。 - **周期任务(`type: "periodic"`)忽略 ACK**:业务 ACK 仅对一次性任务生效,周期任务即使配置了 `ack_url` 也不会进入 `awaiting_ack` 状态。 --- ### 1. Callback 请求(Molens → callback_url) 任务到期时,Worker 向 `callback_url` 发起 HTTP POST 请求。 | 属性 | 值 | |------|-----| | **Method** | `POST` | | **URL** | 创建任务时指定的 `callback_url` | | **Content-Type** | `application/json` | | **超时** | `timeout_ms`(任务级,未指定默认 5000ms) | #### Request Headers | Header | 类型 | 必填 | 说明 | |--------|------|------|------| | `Content-Type` | `string` | 是 | 固定值 `application/json` | | `X-Fire-ID` | `string` | 是 | 本次触发的唯一标识,格式 `{taskID}-{seq}` | | `X-Task-ID` | `string` | 是 | 触发该回调的任务 ID | | `X-Scene` | `string` | 否 | 任务上的场景标签(透传,默认 `default`) | #### Request Body | 字段 | 类型 | 必填 | 说明 | |------|------|------|------| | `payload` | `string` (JSON) | 否 | 创建任务时传入的 `payload`,原样透传 | **示例:** ```http POST /api/myapp/callback HTTP/1.1 Host: 10.0.0.1:8080 Content-Type: application/json X-Fire-ID: t_abc123-42 X-Task-ID: t_abc123 X-Scene: order_reminder "{\"order_id\":\"ORD-20240801\",\"user_id\":\"U1001\"}" ``` #### 回调方响应要求 | 状态码 | 含义 | Molens 行为 | |--------|------|------------| | `2xx` (200-299) | 执行成功 | 记录 `success`,周期任务重新入轮,一次性任务标记 `done` | | `404` | 端点不存在 | **周期任务**:自动设为 `inactive`(停用),不再调度。一次性任务:标记 `failed` | | 其他 `4xx/5xx` | 执行失败 | 触发重试机制,由 Monitor 在 `max_retries` 次数内指数退避重试 | | 超时 / 网络错误 | 连接失败 | 同上,触发重试 | > **注意**:回调方应在业务处理完成后尽快返回 2xx。若处理耗时较长,建议异步处理 + 业务 ACK 确认。 --- ### 2. 业务 ACK 机制 业务 ACK 提供 `At-Least-Once` 语义保障,适合回调方需要异步处理 + 结果确认的场景。 **工作流程:** ``` Molens 派发 callback → 回调方返回 2xx (已接收) ↓ 回调方异步处理业务逻辑 ↓ Molens 创建 ACK 延迟任务 (内部透明) ↓ ACK 任务到期 → Molens 回调 ack_url 验证 ↓ 2xx: ACK 成功,任务完成 非 2xx: TTL-1 后重试,TTL 耗尽则标记 failed ``` **配置方式**(创建任务时): | 参数 | 类型 | 必填 | 默认值 | 说明 | |------|------|------|--------|------| | `ack_url` | `string` | 否 | - | 业务 ACK 回调 URL,回调方处理完成后由 Molens 向此地址验证结果 | | `ack_delay_ms` | `int64` | 否 | `1000` | ACK 延迟毫秒,业务预估处理耗时,到期后 Molens 向 ack_url 回调 | --- ### 3. ACK Callback(Molens → ack_url) ACK 延迟任务到期后,Molens 向 `ack_url` 发起回调,**格式与 Callback 请求完全一致**(Headers + Body 透传)。 | 属性 | 值 | |------|-----| | **Method** | `POST` | | **URL** | 创建任务时指定的 `ack_url` | | **Content-Type** | `application/json` | #### Request Headers | Header | 类型 | 必填 | 说明 | |--------|------|------|------| | `Content-Type` | `string` | 是 | 固定值 `application/json` | | `X-Fire-ID` | `string` | 是 | 本次触发的唯一标识 | | `X-Task-ID` | `string` | 是 | 关联的任务 ID | | `X-Scene` | `string` | 否 | 任务上的场景标签(透传) | #### Request Body Body 为创建任务时传入的 `payload`,原样透传。 > **回调方职责**:收到 ACK callback 时,根据 `X-Fire-ID` 检查对应业务是否处理完成: > - **已完成** → 返回 `2xx`,Molens 标记任务成功 > - **未完成** → 返回 `4xx/5xx`,Molens 在 `DefaultAckTTL=3` 次上限内重试 > - **尚未处理/处理中** → 返回非 `2xx`,等待下次 ACK 回调 --- ### 4. 重试与超时策略 | 配置项 | 层级 | 默认值 | 说明 | |--------|------|--------|------| | `timeout_ms` | 任务 | `5000` | 单次 HTTP 回调超时(毫秒),未指定默认 5s | | `max_retries` | 任务 > 全局 | `3` | 最大重试次数(指数退避) | | `ack_ttl` | 内部 | `3` | ACK 验证最大重试次数 | | `ack_delay_ms` | 任务 | `1000` | ACK 首次回调延迟(毫秒) | **重试退避公式**:`next_retry = 2^retry_count 秒`(第 1 次重试 1s 后,第 2 次 2s 后,第 3 次 4s 后) --- ### 5. 回调响应体回传 每次回调的响应体前 **512 字节** 会被回传至 Leader 写入: - `Task.LastExecutionResult`:最近一次回调响应,覆盖更新 - `ExecutionRecord.ExecutionResult`:每次执行记录独立保存,支持历史追溯 > 可通过 `GET /api/v1/tasks/{id}/executions` 查询周期任务的执行历史记录(含响应体)。 --- ### 6. 周期任务的取消执行 周期任务可通过以下 **4 种方式** 取消执行,适用不同场景: | 方式 | 触发方 | 效果 | 任务数据 | 可恢复 | |------|--------|------|----------|--------| | **删除** | 用户主动调用 API | 物理删除,任务及其执行历史一并移除 | 从索引 + BoltDB + 时间轮三方清除 | 不可恢复 | | **暂停** | 用户主动调用 API | 状态改为 `paused`,移出时间轮 | 保留完整数据 | 可恢复(Resume) | | **回调 404** | 回调方返回 HTTP 404 | 周期任务自动标记为 `inactive`,不再调度 | 保留完整数据 | 需手动恢复 | | **连续失败** | 回调执行失败且重试耗尽 | 达到 `max_fails` 阈值后自动标记为 `inactive` | 保留完整数据 | 需手动恢复 | --- #### 方式一:删除任务 通过 `DELETE /api/v1/tasks/{id}` 触发,经 Raft 共识后物理删除。 ``` 用户 DELETE 请求 → Leader 校验 & Raft Apply → FSM: 从内存索引移除 → FSM: 从 BoltDB 持久化移除 → 调度器: 从时间轮移除 ``` > **注意**:删除是不可逆操作,任务本体及其执行历史会一并删除(经 Raft 三节点一致级联清理),无法恢复。 --- #### 方式二:暂停任务 通过 `POST /api/v1/tasks/{id}/pause` 触发,暂停后任务保留在存储中,可从 UI 或 API 恢复。 **暂停流程:** ``` POST /api/v1/tasks/{id}/pause → Leader Raft Apply → FSM: Status → "paused",更新 UpdatedAt → 调度器: 从时间轮移除任务 ``` **恢复流程:** ``` POST /api/v1/tasks/{id}/resume → Leader Raft Apply → FSM: Status → "pending",重新计算 NextRunAt,Fired = false → 调度器: 重新加入时间轮,按 NextRunAt 继续周期调度 ``` > **适用场景**:临时维护回调方服务、业务低谷期暂停非关键任务、需要人工介入但不希望删除历史记录。 --- #### 方式三:回调响应 404(自动停用) 这是 Molens 的**内置保护机制**:当 Worker 向 `callback_url` 发起 HTTP 请求后收到 `404` 状态码,系统判断回调端点已不存在,自动将周期任务标记为 `inactive` 并停止调度。 **完整链路:** ``` Leader 派发任务到 Worker → Worker HTTP POST callback_url → 回调方返回 404 → Worker 识别非 2xx,提取 StatusCode → Worker 批量 ACK 上报 Leader(携带 status_code=404) → Leader FSM.ProcessBatchAck() ├─ 检测: TaskTypePeriodic && StatusCode == 404 ├─ Status → "inactive" ├─ ExecutionRecord.Result → "not_found" └─ 不加入 reEnqueue(不重新入轮) ``` **关键判别逻辑**(`internal/fsm/fsm.go`): ``` if task.type == "periodic" && ack.status_code == 404: task.status = "inactive" // 停用,不再调度 exec_result = "not_found" // 执行记录标记 else if task.type == "periodic": task.status = "pending" // 普通失败:重新入轮继续调度 task.next_run_at = compute_next_run() reEnqueue(task) // 加入重排队列 ``` **区别要点**: | 回调响应 | 周期任务行为 | 一次性任务行为 | |----------|-------------|---------------| | `2xx` | 计算 NextRunAt,重新入轮 | 标记 `done`,结束 | | `404` | **标记 `inactive`,停止调度** | 标记 `failed`,结束 | | 其他 `4xx/5xx` | 触发重试机制,重试耗尽后标记 `failed` | 同上 | | 超时/网络错误 | 同上 | 同上 | > **适用场景**:回调方服务下线、API 路径变更或废弃时,无需手动逐个停用任务,系统自动检测并停用。 > > **恢复方式**:`inactive` 的任务可通过 `POST /api/v1/tasks/{id}/resume` 手动恢复(前提是回调端点已恢复可用)。 --- #### 方式四:连续失败自动停用 除了回调返回 404,Molens 还内置**连续失败保护**:周期任务在达到重试上限后,其连续失败计数 `FailCount` 递增,当达到 `max_fails` 阈值时,任务自动转为 `inactive` 停止调度。 ``` 回调执行失败(非 404)且重试耗尽 → FailCount++ 并检查是否 >= max_fails ├─ 达标 → Status = "inactive"(自动停用) └─ 未达标 → 重入时间轮,等待下一周期 ``` > `max_fails` 未显式指定时按执行周期自动计算(周期越短阈值越高),也可在创建任务时按任务单独指定。`inactive` 任务统一走 `task_retention_minutes` 保留时长,过期后由清理协程删除。 --- ## 客户端 SDK ### Go ```go import molens "github.com/molens/molens/docs/molens-go" client := molens.NewClient([]string{ "http://127.0.0.1:18081", "http://127.0.0.1:18082", }) resp, _ := client.CreateTask(ctx, &molens.TaskRequest{ Type: "delayed", IntervalMs: 5000, CallbackURL: "http://myapp/callback", }) ``` | 文档 | 说明 | |------|------| | [molens-go/README](docs/molens-go/README.md) | Go SDK 文档 | ### Java (JDK 17+) ```java MolensClient client = new MolensClient( List.of("http://127.0.0.1:18081", "http://127.0.0.1:18082")); TaskResponse resp = client.createTask(new TaskRequest() .setType("delayed").setIntervalMs(5000L) .setCallbackUrl("http://myapp/callback")); ``` | 文档 | 说明 | |------|------| | [molens-java/README](docs/molens-java/README.md) | Java SDK 文档 (JDK 17+) | ### Java (JDK 8+) ```java MolensClient client = new MolensClient( Arrays.asList("http://127.0.0.1:18081", "http://127.0.0.1:18082")); TaskResponse resp = client.createTask(new TaskRequest() .setType("delayed").setIntervalMs(5000L) .setCallbackUrl("http://myapp/callback")); ``` | 文档 | 说明 | |------|------| | [molens-java-8/README](docs/molens-java-8/README.md) | Java SDK 文档 (JDK 8+) | ### SDK 特性 - 集群模式:传入多个节点地址,自动发现 Leader - 故障转移:Leader 切换自动重试并重新发现 - 批量提交:按数量/时间间隔缓冲,合并为单次请求 - 零外部依赖(Go)/ 仅依赖 Jackson(Java) ## 项目结构 ``` molens/ ├── cmd/ │ └── molens/ # 主服务入口 ├── internal/ │ ├── config/ # 配置加载 │ ├── task/ # 任务领域模型 │ ├── timewheel/ # 分层时间轮 │ ├── fsm/ # Raft 状态机 + BoltDB/SQLite 持久化 │ ├── raftnode/ # Raft 节点封装 │ ├── scheduler/ # 调度编排(派发/ACK/监控/清理) │ ├── api/http/ # HTTP API + 前端静态资源 │ ├── rpc/ # 集群内部 gRPC │ └── stats/ # 运行统计 ├── pkg/ │ └── model/ # 公共 API 模型 ├── molens-ui/ # Vue 3 管理界面 ├── docs/ │ ├── api.md # 完整 API 文档 │ ├── deploy.md # 部署文档 │ ├── benchmark.md # 压测文档 │ ├── molens-go/ # Go SDK │ ├── molens-java/ # Java SDK (JDK 17+) │ └── molens-java-8/ # Java SDK (JDK 8+) ├── configs/ # 示例配置文件 ├── deployments/docker/ # Docker 部署 └── Makefile ``` ## 配置说明 ### 节点配置 (configs/node.json) | 配置块 | 关键字段 | 说明 | |--------|----------|------| | 基础 | `node_id`, `data_dir`, `join_addrs` | 节点标识、数据目录、集群发现地址 | | `raft` | `bind_addr`, `election_timeout_ms`, `snapshot_threshold` | Raft 共识参数,见[部署文档](docs/deploy.md#raft-参数) | | `http` | `bind_addr` | HTTP API 监听地址 | | `grpc` | `bind_addr` | 集群内部 gRPC 通信地址 | | `scheduler` | `tick_interval_ms`, `expire_rate_limit_qps` | 时间轮与限流参数 | | `worker` | `concurrency`, `fire_workers`, `dispatch_timeout_ms`, `max_retries`, `monitor_*`, `task_retention_minutes`, `cleanup_interval_ms`, `history_max_records_per_task` | Worker 并发、fire worker、超时、重试、监控、任务清理、执行历史保留 | | 高级 | `log_level` | 日志级别(debug / info / warn / error,默认 info) | ## 数据存储 Molens 采用 BoltDB + SQLite 混合存储: | 文件 | 引擎 | 内容 | 参与 FSM Snapshot | 说明 | |------|------|------|-------------------|------| | `fsm.db` | bbolt | tasks / pending / nodes / stats | 是 | 核心状态,参与 Raft 快照 | | `history.sqlite` | SQLite | executions / url_latency | 否 | 历史数据,每任务保留最近 N 条(默认 200),写入时裁剪 | | `raft.db` | bbolt | Raft 日志 | - | Raft 日志持久化,重启保留走增量追平 | | `snapshots/` | 文件 | Raft 快照文件 | - | LZ4 压缩,定时清理 | --- ## 文档 | 文档 | 内容 | |------|------| | [运行路径](docs/runtime-path.md) | 启动、任务提交流程、调度执行、ACK 处理、故障恢复、优雅关闭的完整路径 | | [API 文档](docs/api.md) | 任务操作、ACK 机制、重试逻辑、去重保障 | | [部署文档](docs/deploy.md) | 配置详解、集群搭建、命令行管理 | | [压测文档](docs/benchmark.md) | molens-bench 使用指南 | ## License MIT