Metadata-Version: 2.5
Name: pulse-scheduler
Version: 1.1.4
Summary: 单机版任务调度平台：DAG 工作流 + cron 定时 + 多进程执行 + Web 控制台
Project-URL: Homepage, https://github.com/pulse-scheduler/pulse-scheduler
Project-URL: Documentation, https://github.com/pulse-scheduler/pulse-scheduler/tree/main/docs
Project-URL: Issues, https://github.com/pulse-scheduler/pulse-scheduler/issues
Author: Pulse Scheduler
License: MIT
Keywords: cron,dag,scheduler,task,workflow
Classifier: Development Status :: 5 - Production/Stable
Classifier: Environment :: Web Environment
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: System Administrators
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: Microsoft :: Windows
Classifier: Operating System :: POSIX :: Linux
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Software Development :: Build Tools
Classifier: Topic :: System :: Monitoring
Requires-Python: >=3.10
Requires-Dist: croniter>=2.0
Requires-Dist: cryptography>=42.0
Requires-Dist: fastapi>=0.110
Requires-Dist: sqlalchemy>=2.0
Requires-Dist: tzdata>=2024.1; platform_system == 'Windows'
Requires-Dist: uvicorn>=0.29
Provides-Extra: mysql
Requires-Dist: pymysql>=1.1; extra == 'mysql'
Description-Content-Type: text/markdown

# Pulse Scheduler ⚡

单机版任务调度平台：DAG 工作流编排 + cron 定时触发 + 多进程执行 + Web 控制台。

```bash
pip install pulse-scheduler
pulse            # 前台启动，浏览器打开 http://127.0.0.1:8765
```

## 功能特性

**工作流编排**
- 浏览器画布编排：拖拽节点、端口连线建依赖、平移缩放、右键菜单、自动布局
- 两种内置任务类型：**Shell**（bash / cmd）与 **SQL**（MySQL，可扩展）
- 节点级配置：任务参数、超时、重试次数与间隔、失败策略（阻塞下游 / 继续执行）、CPU 与内存配额
- 模板变量：`{{run_code}}`、`{{task_code}}`、`{{trigger_time}}`、`{{ds}}`、`{{ds_n1}}`，Shell 另有同名 `PULSE_*` 环境变量

**定时调度**
- 标准 5 字段 cron，输入时实时预览（中文描述 + 未来 5 次触发时间）
- 每个工作流独立的定时配置页（多定时管理），并有全局定时管理视图
- 时区感知（每个定时可指定时区）、启停开关、同工作流内 cron 查重
- misfire 策略：错过触发点默认跳过，可配置补跑（上限 10）
- 工作流下线时定时不触发（页面有醒目告警与一键上线）

**执行引擎**
- 多进程 worker 池（默认 4 个），数据库原子认领，worker 崩溃自动回收重启
- DAG 依赖推进、失败策略、自动重试、超时强杀（跨进程）、取消、任务级重跑与跳过
- 运行实例编码 `RUN-YYYYMMDD-NNNN`，JSONL 任务日志（行级跟尾 / 下载 / 50MB 截断）
- at-least-once 语义：服务重启自动标记中断任务，可一键重跑

**数据源管理**
- 独立管理页面：类型筛选、连接测试、新建 / 编辑 / 删除
- 连接器注册表架构：**MySQL 完整支持**；PostgreSQL、DuckDB 为预留类型（装上驱动即可用）
- 数据源密码 AES-GCM 加密存储，明文永不出 API

**可观测与安全**
- 监控仪表盘：KPI 卡、24h/7d 趋势、队列水位、最近运行
- 单管理员登录即全权限（pbkdf2 + HMAC 签名会话，改密踢出旧会话；支持脚本用静态令牌）
- 登录限速、心跳文件（`pulse status` 不经 API 即可巡检）

**工程特性**
- 零配置直接启动：SQLite + 数据目录自动初始化，首启打印随机管理员密码
- 前端零构建多页应用（无 Node 依赖，Chart.js 已内置），离线可用
- 跨平台：Linux（主要目标）与 Windows 均通过完整测试
- 轻量依赖：FastAPI + SQLAlchemy + croniter + cryptography，无 Redis / Celery / Alembic

## 快速开始

```bash
pip install pulse-scheduler
# SQL 任务需要 MySQL 驱动时：
pip install "pulse-scheduler[mysql]"

pulse                        # 默认 127.0.0.1:8765
pulse serve --host 0.0.0.0 --port 9000 --open
```

首次启动输出示例：

```
==============================================================
  首次启动：已创建管理员账号 admin
  初始密码：fZkNyUtM
  （仅本次打印，请立即登录修改；忘记可用 pulse passwd 重置）
==============================================================
```

登录后自带一个 offline 状态的演示工作流（两个 SHELL 节点串行），上线后在「工作流」页点「运行」即可体验完整链路。

## CLI

| 命令 | 说明 |
|---|---|
| `pulse` / `pulse serve` | 前台启动（`--host --port --data-dir --config --open`） |
| `pulse init` | 仅初始化数据目录 / DB / 种子 / 管理员 |
| `pulse passwd` | 交互式重置管理员密码（改后所有旧会话失效） |
| `pulse status` | 读 `heartbeat.json` 显示服务与 worker 状态（不经 API） |
| `pulse version` | 版本 |

环境变量：`PULSE_HOME`（数据目录，默认 `~/.pulse-scheduler/`）、`PULSE_CONFIG`、`PULSE_PORT`。
优先级：CLI 参数 > 环境变量 > `config.toml` > 默认值。

## 数据目录

```
~/.pulse-scheduler/
├── config.toml      # 可选，全部配置可省略
├── db.sqlite3       # 默认数据库（WAL 模式）
├── secret.key       # 会话签名 + 数据源密码加密密钥（0600，勿泄露）
├── heartbeat.json   # 主进程每秒写入的心跳
└── logs/
    └── RUN-20260830-0001/
        └── task_hello.attempt-1.log   # JSONL 任务日志
```

## 配置（config.toml，全部可省略）

| 键 | 默认 | 说明 |
|---|---|---|
| `server.host` / `port` | 127.0.0.1 / 8765 | 监听地址 |
| `server.shutdown_timeout` | 30 | 优雅停机等待秒数 |
| `database.url` | sqlite:///{data_dir}/db.sqlite3 | **MySQL 切换入口**（见下） |
| `scheduler.tick_seconds` | 1 | 调度扫描间隔 |
| `scheduler.catchup` | false | 错过触发是否补跑（上限 10） |
| `executor.workers` | 4 | 任务执行 worker 进程数（全局执行硬上限） |
| `executor.name` | local | worker 显示名前缀（local-01…） |
| `executor.shell_linux` / `shell_windows` | `bash -lc` / `cmd /c` | 缺省解释器 |
| `executor.log_max_mb` | 50 | 单任务日志文件上限（超限截断标记） |
| `executor.resource_isolation` | auto | auto / cgroupv2 / prlimit / jobobject / none |
| `auth.enabled` | true | 登录开关（false 仅建议本机调试） |
| `auth.session_days` | 7 | 会话有效期 |
| `api.token` | 空 | 非空时启用静态令牌（`X-API-Token`，供脚本/CI） |
| `retention.log_days` / `run_days` | 30 / 90 | 日志 / 实例历史保留 |
| `retention.cleanup_cron` | `30 3 * * *` | 清理计划 |
| `notify.webhook_url` | 空 | run 失败时 POST JSON 事件 |

## 切换 MySQL

```bash
pip install "pulse-scheduler[mysql]"
```

```toml
[database]
url = "mysql+pymysql://user:pass@host:3306/pulse?charset=utf8mb4"
```

首启自动建表迁移，业务代码零改动（SQL 层未使用任何单方言特性）。

## 资源隔离

任务节点的 CPU / 内存配额在隔离可用时为真实限制（Linux `systemd-run` cgroup v2，含
`MemorySwapMax=0` 硬内存上限 → 超限 OOM 退出码 137），自动降级链：
cgroup v2 → prlimit → Windows Job Object → 仅元数据记录。节点抽屉与系统状态页展示当前生效层级。

## 部署

**systemd（Linux）**——示例文件见仓库 `examples/pulse-scheduler.service`：

```bash
cp examples/pulse-scheduler.service /etc/systemd/system/
systemctl daemon-reload && systemctl enable --now pulse-scheduler
journalctl -u pulse-scheduler -f          # 首启密码在日志里
```

**NSSM（Windows 服务）**——见仓库 `examples/nssm-install.md`。

## API 与二次开发

- REST API 前缀 `/api/v1`，OpenAPI 文档自动生成于 `/api/docs`
- 登录会话（HttpOnly Cookie）或 `X-API-Token` 静态令牌
- **任务类型注册表**：实现 `TaskExecutor` 协议并注册即可增加新任务类型
- **数据源连接器注册表**：实现 `connect()/test()` 并注册即可接入新数据库（PostgreSQL / DuckDB 已预留）

## 安全基线

- 默认只监听 `127.0.0.1`；暴露到网络请配置 `api.token` 并套反向代理 TLS
- 数据源密码 AES-GCM 加密存储（防翻库，不防机器 root）
- 会话 HMAC-SHA256 签名，改密即踢出全部旧会话；同 IP 登录失败限速

## License

MIT
