taskwatch 0.2.0__tar.gz → 0.2.3__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. {taskwatch-0.2.0 → taskwatch-0.2.3}/PKG-INFO +341 -1
  2. {taskwatch-0.2.0 → taskwatch-0.2.3}/README.md +340 -0
  3. {taskwatch-0.2.0 → taskwatch-0.2.3}/pyproject.toml +1 -1
  4. {taskwatch-0.2.0 → taskwatch-0.2.3}/taskwatch/cli/log.py +2 -2
  5. {taskwatch-0.2.0 → taskwatch-0.2.3}/taskwatch/core/executor.py +64 -16
  6. {taskwatch-0.2.0 → taskwatch-0.2.3}/taskwatch/core/notifier.py +4 -1
  7. {taskwatch-0.2.0 → taskwatch-0.2.3}/taskwatch/utils/config.py +10 -1
  8. {taskwatch-0.2.0 → taskwatch-0.2.3}/taskwatch/web/api/runs.py +5 -1
  9. {taskwatch-0.2.0 → taskwatch-0.2.3}/taskwatch/web/templates/logs.html +147 -40
  10. {taskwatch-0.2.0 → taskwatch-0.2.3}/taskwatch.egg-info/PKG-INFO +341 -1
  11. {taskwatch-0.2.0 → taskwatch-0.2.3}/setup.cfg +0 -0
  12. {taskwatch-0.2.0 → taskwatch-0.2.3}/taskwatch/__init__.py +0 -0
  13. {taskwatch-0.2.0 → taskwatch-0.2.3}/taskwatch/cli/__init__.py +0 -0
  14. {taskwatch-0.2.0 → taskwatch-0.2.3}/taskwatch/cli/main.py +0 -0
  15. {taskwatch-0.2.0 → taskwatch-0.2.3}/taskwatch/cli/report.py +0 -0
  16. {taskwatch-0.2.0 → taskwatch-0.2.3}/taskwatch/cli/run.py +0 -0
  17. {taskwatch-0.2.0 → taskwatch-0.2.3}/taskwatch/cli/task.py +0 -0
  18. {taskwatch-0.2.0 → taskwatch-0.2.3}/taskwatch/core/__init__.py +0 -0
  19. {taskwatch-0.2.0 → taskwatch-0.2.3}/taskwatch/core/models.py +0 -0
  20. {taskwatch-0.2.0 → taskwatch-0.2.3}/taskwatch/core/reporter.py +0 -0
  21. {taskwatch-0.2.0 → taskwatch-0.2.3}/taskwatch/core/scheduler.py +0 -0
  22. {taskwatch-0.2.0 → taskwatch-0.2.3}/taskwatch/utils/__init__.py +0 -0
  23. {taskwatch-0.2.0 → taskwatch-0.2.3}/taskwatch/utils/logger.py +0 -0
  24. {taskwatch-0.2.0 → taskwatch-0.2.3}/taskwatch/utils/process.py +0 -0
  25. {taskwatch-0.2.0 → taskwatch-0.2.3}/taskwatch/web/__init__.py +0 -0
  26. {taskwatch-0.2.0 → taskwatch-0.2.3}/taskwatch/web/api/__init__.py +0 -0
  27. {taskwatch-0.2.0 → taskwatch-0.2.3}/taskwatch/web/api/reports.py +0 -0
  28. {taskwatch-0.2.0 → taskwatch-0.2.3}/taskwatch/web/api/settings.py +0 -0
  29. {taskwatch-0.2.0 → taskwatch-0.2.3}/taskwatch/web/api/stats.py +0 -0
  30. {taskwatch-0.2.0 → taskwatch-0.2.3}/taskwatch/web/api/tasks.py +0 -0
  31. {taskwatch-0.2.0 → taskwatch-0.2.3}/taskwatch/web/app.py +0 -0
  32. {taskwatch-0.2.0 → taskwatch-0.2.3}/taskwatch/web/routes/__init__.py +0 -0
  33. {taskwatch-0.2.0 → taskwatch-0.2.3}/taskwatch/web/routes/dashboard.py +0 -0
  34. {taskwatch-0.2.0 → taskwatch-0.2.3}/taskwatch/web/routes/logs.py +0 -0
  35. {taskwatch-0.2.0 → taskwatch-0.2.3}/taskwatch/web/routes/reports.py +0 -0
  36. {taskwatch-0.2.0 → taskwatch-0.2.3}/taskwatch/web/routes/settings.py +0 -0
  37. {taskwatch-0.2.0 → taskwatch-0.2.3}/taskwatch/web/routes/tasks.py +0 -0
  38. {taskwatch-0.2.0 → taskwatch-0.2.3}/taskwatch/web/static/css/style.css +0 -0
  39. {taskwatch-0.2.0 → taskwatch-0.2.3}/taskwatch/web/templates/base.html +0 -0
  40. {taskwatch-0.2.0 → taskwatch-0.2.3}/taskwatch/web/templates/dashboard.html +0 -0
  41. {taskwatch-0.2.0 → taskwatch-0.2.3}/taskwatch/web/templates/reports.html +0 -0
  42. {taskwatch-0.2.0 → taskwatch-0.2.3}/taskwatch/web/templates/settings.html +0 -0
  43. {taskwatch-0.2.0 → taskwatch-0.2.3}/taskwatch/web/templates/task_detail.html +0 -0
  44. {taskwatch-0.2.0 → taskwatch-0.2.3}/taskwatch/web/templates/tasks.html +0 -0
  45. {taskwatch-0.2.0 → taskwatch-0.2.3}/taskwatch.egg-info/SOURCES.txt +0 -0
  46. {taskwatch-0.2.0 → taskwatch-0.2.3}/taskwatch.egg-info/dependency_links.txt +0 -0
  47. {taskwatch-0.2.0 → taskwatch-0.2.3}/taskwatch.egg-info/entry_points.txt +0 -0
  48. {taskwatch-0.2.0 → taskwatch-0.2.3}/taskwatch.egg-info/requires.txt +0 -0
  49. {taskwatch-0.2.0 → taskwatch-0.2.3}/taskwatch.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: taskwatch
3
- Version: 0.2.0
3
+ Version: 0.2.3
4
4
  Summary: A lightweight local task scheduler with CLI, web UI, and email reporting
5
5
  Author-email: Chandler <275737875@qq.com>
6
6
  License-Expression: MIT
@@ -28,6 +28,346 @@ Requires-Dist: pytest-asyncio>=0.21.0; extra == "dev"
28
28
 
29
29
  # TaskWatch
30
30
 
31
+ > 轻量级本地任务调度器:一条命令 + 一个 cron 表达式,即可定时执行任务、记录日志、统计结果,并通过邮件发送告警与日报/周报。
32
+
33
+ TaskWatch 面向个人与小团队的本地调度场景,集 **CLI 管理**、**Web 管理界面**、**邮件报告** 于一体,零外部服务依赖(无需 Redis / 数据库服务),安装即用。
34
+
35
+ ## 核心特性
36
+
37
+ - **定时调度** — 支持标准 cron 表达式与 `30m` / `2h` / `1d` 间隔表达式,自动识别
38
+ - **手动触发** — CLI 或 Web UI 一键立即执行任意任务
39
+ - **重试机制** — 失败后自动重试,可配置重试次数与间隔
40
+ - **超时控制** — 超时自动终止任务进程(含进程树)
41
+ - **实时日志** — stdout/stderr 实时落盘,CLI 可 follow 跟踪,Web UI 运行中自动刷新
42
+ - **Web 管理界面** — 仪表盘、任务管理、运行日志、报告中心、系统设置
43
+ - **邮件通知** — 失败即时告警(带冷却机制)、日报/周报自动发送、多 SMTP 账号轮转
44
+ - **零配置存储** — SQLite 本地持久化(WAL 模式)+ TOML 配置文件
45
+
46
+ ## 目录
47
+
48
+ - [快速启动](#快速启动)
49
+ - [详细教程](#详细教程)
50
+ - [配置说明](#配置说明)
51
+ - [项目架构](#项目架构)
52
+ - [开发指南](#开发指南)
53
+ - [License](#license)
54
+
55
+ ---
56
+
57
+ ## 快速启动
58
+
59
+ ### 环境要求
60
+
61
+ - Python >= 3.9(支持 3.9 ~ 3.12)
62
+ - pip
63
+
64
+ ### 安装
65
+
66
+ ```bash
67
+ # 进入项目根目录(pyproject.toml 所在目录)
68
+ cd taskwatch
69
+
70
+ # 安装
71
+ pip install .
72
+
73
+ # 或开发模式安装(代码修改即时生效)
74
+ pip install -e .
75
+ ```
76
+
77
+ 安装后会注册两个等价的命令入口:`tw` 和 `taskwatch`。
78
+
79
+ ### 5 分钟跑起来
80
+
81
+ ```bash
82
+ # 1. 初始化:在当前目录生成 config.toml、taskwatch.db、logs/
83
+ tw init
84
+
85
+ # 2. 添加一个任务:每天早上 9 点执行
86
+ tw task add --name "hello" --command "echo Hello TaskWatch" --schedule "0 9 * * *"
87
+
88
+ # 3. 立即手动执行一次,验证是否工作
89
+ tw task run 1
90
+
91
+ # 4. 启动 Web 管理界面(内嵌调度器,任务会按计划自动运行)
92
+ tw web
93
+ ```
94
+
95
+ 浏览器访问 **http://127.0.0.1:8899**,即可在仪表盘查看统计、在「运行日志」页面查看刚才的输出。
96
+
97
+ > 如果只需要纯命令行调度:`tw run`(前台运行,Ctrl+C 停止)。
98
+ >
99
+ > ⚠️ `tw web` 已内嵌调度器,请勿与 `tw run` 同时运行,否则任务会被重复调度。
100
+
101
+ ---
102
+
103
+ ## 详细教程
104
+
105
+ ### CLI 常用命令
106
+
107
+ #### `tw init` — 初始化
108
+
109
+ 在当前目录创建数据目录、SQLite 数据库和默认配置文件,并可交互式配置 SMTP。
110
+
111
+ ```bash
112
+ tw init
113
+ ```
114
+
115
+ #### `tw task` — 任务管理
116
+
117
+ | 命令 | 说明 | 示例 |
118
+ |------|------|------|
119
+ | `tw task add` | 添加任务 | `tw task add -n "backup" -c "python backup.py" -s "0 2 * * *"` |
120
+ | `tw task list` | 列出任务 | `tw task list --status enabled --search etl` |
121
+ | `tw task show <ID>` | 任务详情与运行统计 | `tw task show 1` |
122
+ | `tw task edit <ID>` | 编辑任务 | `tw task edit 1 --schedule "30 8 * * *"` |
123
+ | `tw task rm <ID>` | 删除任务(`-f` 跳过确认) | `tw task rm 1 -f` |
124
+ | `tw task enable <ID>` | 启用任务 | `tw task enable 1` |
125
+ | `tw task disable <ID>` | 禁用任务 | `tw task disable 1` |
126
+ | `tw task run <ID>` | 手动触发一次运行 | `tw task run 1` |
127
+
128
+ #### `tw run` — 启动调度器
129
+
130
+ ```bash
131
+ tw run # 前台运行,Ctrl+C 停止
132
+ tw run --daemon # 后台守护进程(仅 Unix 系统)
133
+ ```
134
+
135
+ #### `tw log` — 查看日志
136
+
137
+ ```bash
138
+ tw log 1 # 查看任务 1 的最近运行记录 + 最新日志
139
+ tw log 1 --run-id 42 # 查看指定运行记录的日志
140
+ tw log 1 --tail 50 # 显示最近 50 行
141
+ tw log 1 --follow # 实时跟踪日志(类似 tail -f)
142
+ ```
143
+
144
+ #### `tw report` — 生成报告
145
+
146
+ ```bash
147
+ tw report daily # 生成今日日报
148
+ tw report daily 2026-07-22 --send # 生成指定日期日报并邮件发送
149
+ tw report weekly # 生成本周周报
150
+ tw report weekly 2026-07-14 2026-07-20 --send
151
+ ```
152
+
153
+ #### `tw config` — 配置管理
154
+
155
+ ```bash
156
+ tw config --list # 查看全部配置
157
+ tw config smtp.host # 查看单项
158
+ tw config smtp.host smtp.qq.com # 修改单项
159
+ ```
160
+
161
+ #### `tw mail` — 邮件测试
162
+
163
+ ```bash
164
+ tw mail test # 发送测试邮件,验证 SMTP 配置
165
+ ```
166
+
167
+ #### `tw web` — Web 管理界面
168
+
169
+ ```bash
170
+ tw web # 默认 127.0.0.1:8899,自动打开浏览器
171
+ tw web --host 0.0.0.0 --port 9000 # 自定义监听地址
172
+ tw web --no-browser # 不自动打开浏览器
173
+ ```
174
+
175
+ ### Web UI 功能说明
176
+
177
+ | 页面 | 路径 | 功能 |
178
+ |------|------|------|
179
+ | 仪表盘 | `/` | 任务总数、运行统计、成功率、近 7 天趋势图、最近运行记录 |
180
+ | 任务管理 | `/tasks` | 任务列表、搜索过滤、新建/编辑/删除、启用/禁用、手动运行 |
181
+ | 任务详情 | `/tasks/{id}` | 任务配置、运行统计(总次数/成功率/平均耗时)、最近运行记录 |
182
+ | 运行日志 | `/logs` | 多条件过滤(任务/状态/触发方式/时间范围/关键词)、分页、日志详情弹窗(运行中每 3 秒自动刷新)、终止运行中任务 |
183
+ | 报告中心 | `/reports` | 日报/周报历史、手动生成、查看详情、重新发送邮件 |
184
+ | 系统设置 | `/settings` | SMTP 配置、报告时间、告警配置、发送测试邮件、清理日志 |
185
+
186
+ ### 任务配置项说明
187
+
188
+ | 配置项 | CLI 参数 | 说明 |
189
+ |--------|----------|------|
190
+ | `name` | `--name` / `-n` | 任务名称(必填) |
191
+ | `command` | `--command` / `-c` | 执行命令,通过 shell 执行(必填) |
192
+ | `schedule` | `--schedule` / `-s` | 调度表达式,见下方说明(必填) |
193
+ | `working_dir` | `--working-dir` / `-w` | 工作目录,默认为当前目录 |
194
+ | `env` | `--env` | 环境变量,格式 `KEY1=val1,KEY2=val2` |
195
+ | `timeout` | `--timeout` / `-t` | 超时秒数,默认跟随 `config.toml` 的 `timeout.default_timeout` |
196
+ | `retry` | `--retry` / `-r` | 失败最大重试次数,默认跟随 `retry.default_retry` |
197
+ | `retry_interval` | `--retry-interval` | 重试间隔秒数,默认跟随 `retry.default_retry_interval` |
198
+ | `interpreter` | `--interpreter` | Python 解释器路径(写入 `TASKWATCH_INTERPRETER` 环境变量) |
199
+ | `tags` | `--tags` | 标签,逗号分隔,用于搜索分组 |
200
+ | `notify` | `--notify` | 通知策略:`on_failure`(默认)/ `always` / `never` |
201
+
202
+ **调度表达式(自动识别类型):**
203
+
204
+ | 类型 | 格式 | 示例 |
205
+ |------|------|------|
206
+ | cron | 5 位标准表达式:`分 时 日 月 周` | `0 9 * * *`(每天 9:00) |
207
+ | cron | 6 位带秒:`秒 分 时 日 月 周` | `30 0 9 * * *`(每天 9:00:30) |
208
+ | interval | 数字 + 单位(m/h/d) | `30m`、`2h`、`1d`,等价于 `every 30m` 等 |
209
+
210
+ ---
211
+
212
+ ## 配置说明
213
+
214
+ ### 配置文件位置与格式
215
+
216
+ 配置文件为工作目录下的 **`config.toml`**(TOML 格式),首次运行 `tw init` 时自动生成。可通过 `tw config` 命令或 Web UI「系统设置」页面修改,也可以直接编辑文件(修改后重启服务生效)。
217
+
218
+ ### 完整配置示例(带注释)
219
+
220
+ 以下为 `tw init` 生成的默认配置及各项说明:
221
+
222
+ ```toml
223
+ [core]
224
+ database_path = "./taskwatch.db" # SQLite 数据库文件路径
225
+ log_dir = "./logs" # 任务日志目录
226
+ pid_file = "./taskwatch.pid" # 调度器 PID 文件路径
227
+ force_utf8_codepage = true # Windows 下自动为命令添加 chcp 65001 前缀,
228
+ # 解决 CMD 中文/emoji 乱码;不需要可设为 false
229
+
230
+ [smtp]
231
+ enabled = false # 是否启用邮件通知
232
+ host = "smtp.gmail.com" # SMTP 服务器
233
+ port = 587 # SMTP 端口
234
+ use_tls = true # 是否使用 TLS
235
+ username = "" # SMTP 用户名
236
+ password = "" # SMTP 密码(推荐用环境变量 TASKWATCH_SMTP_PASSWORD 代替)
237
+ from_addr = "" # 发件人地址
238
+ to_addrs = [] # 收件人列表
239
+
240
+ [retry]
241
+ default_retry = 0 # 任务未指定时的默认重试次数(0 表示不重试)
242
+ default_retry_interval = 60 # 默认重试间隔(秒)
243
+
244
+ [timeout]
245
+ default_timeout = 3600 # 任务未指定时的默认超时(秒)
246
+
247
+ [logging]
248
+ max_log_files = 100 # 日志文件保留数量上限
249
+ max_log_age_days = 30 # 日志保留天数
250
+
251
+ [web]
252
+ host = "127.0.0.1" # Web 监听地址
253
+ port = 8899 # Web 监听端口
254
+ auto_open_browser = true # 启动 tw web 时自动打开浏览器
255
+
256
+ [report]
257
+ daily_enabled = true # 是否启用日报
258
+ daily_time = "10:00" # 日报发送时间
259
+ weekly_enabled = true # 是否启用周报
260
+ weekly_day = "monday" # 周报发送星期
261
+ weekly_time = "11:00" # 周报发送时间
262
+
263
+ [alert]
264
+ enabled = true # 是否启用任务失败告警
265
+ cooldown_minutes = 10 # 同一任务的告警冷却时间(分钟),防止邮件轰炸
266
+ ```
267
+
268
+ > 多 SMTP 账号轮转:可在 `[smtp]` 下配置 `accounts` 账号列表,发信时自动轮转,规避单账号频率限制。
269
+
270
+ ---
271
+
272
+ ## 项目架构
273
+
274
+ ### 目录结构
275
+
276
+ ```
277
+ taskwatch/
278
+ ├── pyproject.toml # 项目元数据、依赖、命令入口(tw / taskwatch)
279
+ ├── docs/ # 设计文档(变更规格与审查记录)
280
+ └── taskwatch/ # 主包
281
+ ├── cli/ # 命令行层(Typer + Rich)
282
+ │ ├── main.py # 主应用:init / config / mail / web
283
+ │ ├── task.py # 任务管理:add/list/show/edit/rm/enable/disable/run
284
+ │ ├── run.py # 启动调度器:tw run [--daemon]
285
+ │ ├── log.py # 日志查看:tw log [--tail/--follow/--run-id]
286
+ │ └── report.py # 报告生成:daily / weekly
287
+ ├── core/ # 核心业务层(不依赖任何 UI 框架)
288
+ │ ├── models.py # SQLite 数据层(tasks / runs / reports 三表 CRUD)
289
+ │ ├── scheduler.py # APScheduler 调度引擎(cron/interval 触发、孤儿运行清理)
290
+ │ ├── executor.py # 子进程执行器(超时/重试、实时日志捕获、输出智能解码)
291
+ │ ├── notifier.py # SMTP 通知(失败告警、日报/周报发送、多账号轮转、冷却)
292
+ │ └── reporter.py # 日报/周报 HTML 生成引擎
293
+ ├── utils/ # 工具层
294
+ │ ├── config.py # TOML 配置管理(全局单例,默认值 + 用户覆盖深合并)
295
+ │ ├── logger.py # 日志工具
296
+ │ └── process.py # 进程工具(按 PID 终止进程、存活检测)
297
+ └── web/ # Web 展示层(FastAPI)
298
+ ├── app.py # 应用工厂 create_app(),启动时内嵌调度器
299
+ ├── api/ # REST API(/api/stats、tasks、runs、reports、settings)
300
+ ├── routes/ # 页面路由(Jinja2 服务端渲染)
301
+ ├── static/css/ # 自定义样式
302
+ └── templates/ # HTML 模板(Tailwind CSS + HTMX + Chart.js,CDN 引入)
303
+ ```
304
+
305
+ ### 核心数据流
306
+
307
+ ```
308
+ tw run / tw web(内嵌调度器)
309
+ │ cron / interval 定时触发,或 CLI / Web 手动触发
310
+ ▼
311
+ TaskExecutor 子进程执行(shell 执行命令)
312
+ │ 实时捕获 stdout/stderr,逐行智能解码(UTF-8 优先,系统编码回退)
313
+ ▼
314
+ 日志文件 logs/<task_id>/*.log + SQLite runs 表(状态/退出码/输出摘要)
315
+ │
316
+ ├──▶ Web UI:/logs 页面通过 /api/runs/{id}/stream 实时查看
317
+ ├──▶ CLI:tw log / tw task show
318
+ └──▶ 邮件:失败告警(Notifier)+ 日报/周报(Reporter)
319
+ ```
320
+
321
+ ### 技术栈
322
+
323
+ | 技术 | 用途 |
324
+ |------|------|
325
+ | Typer + Rich | CLI 框架与终端美化输出(表格、颜色) |
326
+ | FastAPI + Uvicorn | Web 框架与 ASGI 服务器 |
327
+ | Jinja2 | HTML 模板引擎(服务端渲染) |
328
+ | Tailwind CSS / HTMX / Chart.js | 前端样式、交互增强、趋势图表(全部 CDN 引入,零构建) |
329
+ | APScheduler | 调度引擎(BackgroundScheduler,cron/interval 触发器) |
330
+ | SQLite(WAL 模式) | 数据持久化,零配置、支持并发读写 |
331
+ | tomllib / tomli-w | TOML 配置读写(Python < 3.11 使用 tomli) |
332
+ | smtplib | 邮件发送(标准库) |
333
+
334
+ ---
335
+
336
+ ## 开发指南
337
+
338
+ ### 本地开发环境
339
+
340
+ ```bash
341
+ # 1. 克隆项目并进入目录
342
+ cd taskwatch
343
+
344
+ # 2. 以开发模式安装(含 pytest 等开发依赖)
345
+ pip install -e ".[dev]"
346
+
347
+ # 3. 验证安装
348
+ tw --help
349
+ ```
350
+
351
+ 开发时数据文件(`config.toml`、`taskwatch.db`、`logs/`)生成在**当前工作目录**,建议在项目外单独建一个工作目录运行 `tw init`,避免污染源码目录。
352
+
353
+ ### 运行测试
354
+
355
+ 项目使用 pytest 作为测试框架(已包含在 `dev` 可选依赖中):
356
+
357
+ ```bash
358
+ pytest
359
+ ```
360
+
361
+ > 当前仓库未内置 `tests/` 目录;新增测试文件后 pytest 会自动收集执行。
362
+ > 修改代码后可先用 `python -m py_compile <文件>` 做语法快速检查。
363
+
364
+ ---
365
+
366
+ ## License
367
+
368
+ [MIT](https://opensource.org/licenses/MIT)
369
+ # TaskWatch
370
+
31
371
  轻量级本地任务调度器,集 CLI 管理、Web 仪表盘和邮件报告于一体。
32
372
 
33
373
  ## 核心特性
@@ -1,5 +1,345 @@
1
1
  # TaskWatch
2
2
 
3
+ > 轻量级本地任务调度器:一条命令 + 一个 cron 表达式,即可定时执行任务、记录日志、统计结果,并通过邮件发送告警与日报/周报。
4
+
5
+ TaskWatch 面向个人与小团队的本地调度场景,集 **CLI 管理**、**Web 管理界面**、**邮件报告** 于一体,零外部服务依赖(无需 Redis / 数据库服务),安装即用。
6
+
7
+ ## 核心特性
8
+
9
+ - **定时调度** — 支持标准 cron 表达式与 `30m` / `2h` / `1d` 间隔表达式,自动识别
10
+ - **手动触发** — CLI 或 Web UI 一键立即执行任意任务
11
+ - **重试机制** — 失败后自动重试,可配置重试次数与间隔
12
+ - **超时控制** — 超时自动终止任务进程(含进程树)
13
+ - **实时日志** — stdout/stderr 实时落盘,CLI 可 follow 跟踪,Web UI 运行中自动刷新
14
+ - **Web 管理界面** — 仪表盘、任务管理、运行日志、报告中心、系统设置
15
+ - **邮件通知** — 失败即时告警(带冷却机制)、日报/周报自动发送、多 SMTP 账号轮转
16
+ - **零配置存储** — SQLite 本地持久化(WAL 模式)+ TOML 配置文件
17
+
18
+ ## 目录
19
+
20
+ - [快速启动](#快速启动)
21
+ - [详细教程](#详细教程)
22
+ - [配置说明](#配置说明)
23
+ - [项目架构](#项目架构)
24
+ - [开发指南](#开发指南)
25
+ - [License](#license)
26
+
27
+ ---
28
+
29
+ ## 快速启动
30
+
31
+ ### 环境要求
32
+
33
+ - Python >= 3.9(支持 3.9 ~ 3.12)
34
+ - pip
35
+
36
+ ### 安装
37
+
38
+ ```bash
39
+ # 进入项目根目录(pyproject.toml 所在目录)
40
+ cd taskwatch
41
+
42
+ # 安装
43
+ pip install .
44
+
45
+ # 或开发模式安装(代码修改即时生效)
46
+ pip install -e .
47
+ ```
48
+
49
+ 安装后会注册两个等价的命令入口:`tw` 和 `taskwatch`。
50
+
51
+ ### 5 分钟跑起来
52
+
53
+ ```bash
54
+ # 1. 初始化:在当前目录生成 config.toml、taskwatch.db、logs/
55
+ tw init
56
+
57
+ # 2. 添加一个任务:每天早上 9 点执行
58
+ tw task add --name "hello" --command "echo Hello TaskWatch" --schedule "0 9 * * *"
59
+
60
+ # 3. 立即手动执行一次,验证是否工作
61
+ tw task run 1
62
+
63
+ # 4. 启动 Web 管理界面(内嵌调度器,任务会按计划自动运行)
64
+ tw web
65
+ ```
66
+
67
+ 浏览器访问 **http://127.0.0.1:8899**,即可在仪表盘查看统计、在「运行日志」页面查看刚才的输出。
68
+
69
+ > 如果只需要纯命令行调度:`tw run`(前台运行,Ctrl+C 停止)。
70
+ >
71
+ > ⚠️ `tw web` 已内嵌调度器,请勿与 `tw run` 同时运行,否则任务会被重复调度。
72
+
73
+ ---
74
+
75
+ ## 详细教程
76
+
77
+ ### CLI 常用命令
78
+
79
+ #### `tw init` — 初始化
80
+
81
+ 在当前目录创建数据目录、SQLite 数据库和默认配置文件,并可交互式配置 SMTP。
82
+
83
+ ```bash
84
+ tw init
85
+ ```
86
+
87
+ #### `tw task` — 任务管理
88
+
89
+ | 命令 | 说明 | 示例 |
90
+ |------|------|------|
91
+ | `tw task add` | 添加任务 | `tw task add -n "backup" -c "python backup.py" -s "0 2 * * *"` |
92
+ | `tw task list` | 列出任务 | `tw task list --status enabled --search etl` |
93
+ | `tw task show <ID>` | 任务详情与运行统计 | `tw task show 1` |
94
+ | `tw task edit <ID>` | 编辑任务 | `tw task edit 1 --schedule "30 8 * * *"` |
95
+ | `tw task rm <ID>` | 删除任务(`-f` 跳过确认) | `tw task rm 1 -f` |
96
+ | `tw task enable <ID>` | 启用任务 | `tw task enable 1` |
97
+ | `tw task disable <ID>` | 禁用任务 | `tw task disable 1` |
98
+ | `tw task run <ID>` | 手动触发一次运行 | `tw task run 1` |
99
+
100
+ #### `tw run` — 启动调度器
101
+
102
+ ```bash
103
+ tw run # 前台运行,Ctrl+C 停止
104
+ tw run --daemon # 后台守护进程(仅 Unix 系统)
105
+ ```
106
+
107
+ #### `tw log` — 查看日志
108
+
109
+ ```bash
110
+ tw log 1 # 查看任务 1 的最近运行记录 + 最新日志
111
+ tw log 1 --run-id 42 # 查看指定运行记录的日志
112
+ tw log 1 --tail 50 # 显示最近 50 行
113
+ tw log 1 --follow # 实时跟踪日志(类似 tail -f)
114
+ ```
115
+
116
+ #### `tw report` — 生成报告
117
+
118
+ ```bash
119
+ tw report daily # 生成今日日报
120
+ tw report daily 2026-07-22 --send # 生成指定日期日报并邮件发送
121
+ tw report weekly # 生成本周周报
122
+ tw report weekly 2026-07-14 2026-07-20 --send
123
+ ```
124
+
125
+ #### `tw config` — 配置管理
126
+
127
+ ```bash
128
+ tw config --list # 查看全部配置
129
+ tw config smtp.host # 查看单项
130
+ tw config smtp.host smtp.qq.com # 修改单项
131
+ ```
132
+
133
+ #### `tw mail` — 邮件测试
134
+
135
+ ```bash
136
+ tw mail test # 发送测试邮件,验证 SMTP 配置
137
+ ```
138
+
139
+ #### `tw web` — Web 管理界面
140
+
141
+ ```bash
142
+ tw web # 默认 127.0.0.1:8899,自动打开浏览器
143
+ tw web --host 0.0.0.0 --port 9000 # 自定义监听地址
144
+ tw web --no-browser # 不自动打开浏览器
145
+ ```
146
+
147
+ ### Web UI 功能说明
148
+
149
+ | 页面 | 路径 | 功能 |
150
+ |------|------|------|
151
+ | 仪表盘 | `/` | 任务总数、运行统计、成功率、近 7 天趋势图、最近运行记录 |
152
+ | 任务管理 | `/tasks` | 任务列表、搜索过滤、新建/编辑/删除、启用/禁用、手动运行 |
153
+ | 任务详情 | `/tasks/{id}` | 任务配置、运行统计(总次数/成功率/平均耗时)、最近运行记录 |
154
+ | 运行日志 | `/logs` | 多条件过滤(任务/状态/触发方式/时间范围/关键词)、分页、日志详情弹窗(运行中每 3 秒自动刷新)、终止运行中任务 |
155
+ | 报告中心 | `/reports` | 日报/周报历史、手动生成、查看详情、重新发送邮件 |
156
+ | 系统设置 | `/settings` | SMTP 配置、报告时间、告警配置、发送测试邮件、清理日志 |
157
+
158
+ ### 任务配置项说明
159
+
160
+ | 配置项 | CLI 参数 | 说明 |
161
+ |--------|----------|------|
162
+ | `name` | `--name` / `-n` | 任务名称(必填) |
163
+ | `command` | `--command` / `-c` | 执行命令,通过 shell 执行(必填) |
164
+ | `schedule` | `--schedule` / `-s` | 调度表达式,见下方说明(必填) |
165
+ | `working_dir` | `--working-dir` / `-w` | 工作目录,默认为当前目录 |
166
+ | `env` | `--env` | 环境变量,格式 `KEY1=val1,KEY2=val2` |
167
+ | `timeout` | `--timeout` / `-t` | 超时秒数,默认跟随 `config.toml` 的 `timeout.default_timeout` |
168
+ | `retry` | `--retry` / `-r` | 失败最大重试次数,默认跟随 `retry.default_retry` |
169
+ | `retry_interval` | `--retry-interval` | 重试间隔秒数,默认跟随 `retry.default_retry_interval` |
170
+ | `interpreter` | `--interpreter` | Python 解释器路径(写入 `TASKWATCH_INTERPRETER` 环境变量) |
171
+ | `tags` | `--tags` | 标签,逗号分隔,用于搜索分组 |
172
+ | `notify` | `--notify` | 通知策略:`on_failure`(默认)/ `always` / `never` |
173
+
174
+ **调度表达式(自动识别类型):**
175
+
176
+ | 类型 | 格式 | 示例 |
177
+ |------|------|------|
178
+ | cron | 5 位标准表达式:`分 时 日 月 周` | `0 9 * * *`(每天 9:00) |
179
+ | cron | 6 位带秒:`秒 分 时 日 月 周` | `30 0 9 * * *`(每天 9:00:30) |
180
+ | interval | 数字 + 单位(m/h/d) | `30m`、`2h`、`1d`,等价于 `every 30m` 等 |
181
+
182
+ ---
183
+
184
+ ## 配置说明
185
+
186
+ ### 配置文件位置与格式
187
+
188
+ 配置文件为工作目录下的 **`config.toml`**(TOML 格式),首次运行 `tw init` 时自动生成。可通过 `tw config` 命令或 Web UI「系统设置」页面修改,也可以直接编辑文件(修改后重启服务生效)。
189
+
190
+ ### 完整配置示例(带注释)
191
+
192
+ 以下为 `tw init` 生成的默认配置及各项说明:
193
+
194
+ ```toml
195
+ [core]
196
+ database_path = "./taskwatch.db" # SQLite 数据库文件路径
197
+ log_dir = "./logs" # 任务日志目录
198
+ pid_file = "./taskwatch.pid" # 调度器 PID 文件路径
199
+ force_utf8_codepage = true # Windows 下自动为命令添加 chcp 65001 前缀,
200
+ # 解决 CMD 中文/emoji 乱码;不需要可设为 false
201
+
202
+ [smtp]
203
+ enabled = false # 是否启用邮件通知
204
+ host = "smtp.gmail.com" # SMTP 服务器
205
+ port = 587 # SMTP 端口
206
+ use_tls = true # 是否使用 TLS
207
+ username = "" # SMTP 用户名
208
+ password = "" # SMTP 密码(推荐用环境变量 TASKWATCH_SMTP_PASSWORD 代替)
209
+ from_addr = "" # 发件人地址
210
+ to_addrs = [] # 收件人列表
211
+
212
+ [retry]
213
+ default_retry = 0 # 任务未指定时的默认重试次数(0 表示不重试)
214
+ default_retry_interval = 60 # 默认重试间隔(秒)
215
+
216
+ [timeout]
217
+ default_timeout = 3600 # 任务未指定时的默认超时(秒)
218
+
219
+ [logging]
220
+ max_log_files = 100 # 日志文件保留数量上限
221
+ max_log_age_days = 30 # 日志保留天数
222
+
223
+ [web]
224
+ host = "127.0.0.1" # Web 监听地址
225
+ port = 8899 # Web 监听端口
226
+ auto_open_browser = true # 启动 tw web 时自动打开浏览器
227
+
228
+ [report]
229
+ daily_enabled = true # 是否启用日报
230
+ daily_time = "10:00" # 日报发送时间
231
+ weekly_enabled = true # 是否启用周报
232
+ weekly_day = "monday" # 周报发送星期
233
+ weekly_time = "11:00" # 周报发送时间
234
+
235
+ [alert]
236
+ enabled = true # 是否启用任务失败告警
237
+ cooldown_minutes = 10 # 同一任务的告警冷却时间(分钟),防止邮件轰炸
238
+ ```
239
+
240
+ > 多 SMTP 账号轮转:可在 `[smtp]` 下配置 `accounts` 账号列表,发信时自动轮转,规避单账号频率限制。
241
+
242
+ ---
243
+
244
+ ## 项目架构
245
+
246
+ ### 目录结构
247
+
248
+ ```
249
+ taskwatch/
250
+ ├── pyproject.toml # 项目元数据、依赖、命令入口(tw / taskwatch)
251
+ ├── docs/ # 设计文档(变更规格与审查记录)
252
+ └── taskwatch/ # 主包
253
+ ├── cli/ # 命令行层(Typer + Rich)
254
+ │ ├── main.py # 主应用:init / config / mail / web
255
+ │ ├── task.py # 任务管理:add/list/show/edit/rm/enable/disable/run
256
+ │ ├── run.py # 启动调度器:tw run [--daemon]
257
+ │ ├── log.py # 日志查看:tw log [--tail/--follow/--run-id]
258
+ │ └── report.py # 报告生成:daily / weekly
259
+ ├── core/ # 核心业务层(不依赖任何 UI 框架)
260
+ │ ├── models.py # SQLite 数据层(tasks / runs / reports 三表 CRUD)
261
+ │ ├── scheduler.py # APScheduler 调度引擎(cron/interval 触发、孤儿运行清理)
262
+ │ ├── executor.py # 子进程执行器(超时/重试、实时日志捕获、输出智能解码)
263
+ │ ├── notifier.py # SMTP 通知(失败告警、日报/周报发送、多账号轮转、冷却)
264
+ │ └── reporter.py # 日报/周报 HTML 生成引擎
265
+ ├── utils/ # 工具层
266
+ │ ├── config.py # TOML 配置管理(全局单例,默认值 + 用户覆盖深合并)
267
+ │ ├── logger.py # 日志工具
268
+ │ └── process.py # 进程工具(按 PID 终止进程、存活检测)
269
+ └── web/ # Web 展示层(FastAPI)
270
+ ├── app.py # 应用工厂 create_app(),启动时内嵌调度器
271
+ ├── api/ # REST API(/api/stats、tasks、runs、reports、settings)
272
+ ├── routes/ # 页面路由(Jinja2 服务端渲染)
273
+ ├── static/css/ # 自定义样式
274
+ └── templates/ # HTML 模板(Tailwind CSS + HTMX + Chart.js,CDN 引入)
275
+ ```
276
+
277
+ ### 核心数据流
278
+
279
+ ```
280
+ tw run / tw web(内嵌调度器)
281
+ │ cron / interval 定时触发,或 CLI / Web 手动触发
282
+ ▼
283
+ TaskExecutor 子进程执行(shell 执行命令)
284
+ │ 实时捕获 stdout/stderr,逐行智能解码(UTF-8 优先,系统编码回退)
285
+ ▼
286
+ 日志文件 logs/<task_id>/*.log + SQLite runs 表(状态/退出码/输出摘要)
287
+ │
288
+ ├──▶ Web UI:/logs 页面通过 /api/runs/{id}/stream 实时查看
289
+ ├──▶ CLI:tw log / tw task show
290
+ └──▶ 邮件:失败告警(Notifier)+ 日报/周报(Reporter)
291
+ ```
292
+
293
+ ### 技术栈
294
+
295
+ | 技术 | 用途 |
296
+ |------|------|
297
+ | Typer + Rich | CLI 框架与终端美化输出(表格、颜色) |
298
+ | FastAPI + Uvicorn | Web 框架与 ASGI 服务器 |
299
+ | Jinja2 | HTML 模板引擎(服务端渲染) |
300
+ | Tailwind CSS / HTMX / Chart.js | 前端样式、交互增强、趋势图表(全部 CDN 引入,零构建) |
301
+ | APScheduler | 调度引擎(BackgroundScheduler,cron/interval 触发器) |
302
+ | SQLite(WAL 模式) | 数据持久化,零配置、支持并发读写 |
303
+ | tomllib / tomli-w | TOML 配置读写(Python < 3.11 使用 tomli) |
304
+ | smtplib | 邮件发送(标准库) |
305
+
306
+ ---
307
+
308
+ ## 开发指南
309
+
310
+ ### 本地开发环境
311
+
312
+ ```bash
313
+ # 1. 克隆项目并进入目录
314
+ cd taskwatch
315
+
316
+ # 2. 以开发模式安装(含 pytest 等开发依赖)
317
+ pip install -e ".[dev]"
318
+
319
+ # 3. 验证安装
320
+ tw --help
321
+ ```
322
+
323
+ 开发时数据文件(`config.toml`、`taskwatch.db`、`logs/`)生成在**当前工作目录**,建议在项目外单独建一个工作目录运行 `tw init`,避免污染源码目录。
324
+
325
+ ### 运行测试
326
+
327
+ 项目使用 pytest 作为测试框架(已包含在 `dev` 可选依赖中):
328
+
329
+ ```bash
330
+ pytest
331
+ ```
332
+
333
+ > 当前仓库未内置 `tests/` 目录;新增测试文件后 pytest 会自动收集执行。
334
+ > 修改代码后可先用 `python -m py_compile <文件>` 做语法快速检查。
335
+
336
+ ---
337
+
338
+ ## License
339
+
340
+ [MIT](https://opensource.org/licenses/MIT)
341
+ # TaskWatch
342
+
3
343
  轻量级本地任务调度器,集 CLI 管理、Web 仪表盘和邮件报告于一体。
4
344
 
5
345
  ## 核心特性