15. Task Scheduler 任务调度器
V1 — 1个用户:浏览器定时器
Section titled “V1 — 1个用户:浏览器定时器”你做了一个番茄钟应用,需要在浏览器端实现定时提醒:25分钟工作 + 5分钟休息循环。
你要解决什么
Section titled “你要解决什么”用纯JavaScript实现定时任务管理,支持创建、取消、查看定时任务。
给AI的Prompt
Section titled “给AI的Prompt”帮我用纯HTML+JavaScript实现一个浏览器端任务调度器:
1. 番茄钟核心: - 25分钟倒计时 → 弹出休息通知 - 5分钟休息倒计时 → 弹出工作通知 - 每4个番茄钟一次15分钟长休息2. 通用定时任务管理: - 创建任务:名称、执行时间(延迟X秒 或 指定时刻)、是否重复 - 任务列表显示:名称、下次执行时间、状态(等待/已执行/已取消) - 取消任务、暂停任务3. 调度器实现: - 内部用setTimeout实现 - 一个调度器对象管理所有任务ID和timer引用 - 提供add/cancel/pause/resume方法4. 持久化: - 任务定义存localStorage - 刷新页面后重新计算剩余时间,重新调度5. Notification API: - 任务到期时用浏览器Notification弹通知 - 请求通知权限
纯原生JS,不用框架。- 番茄钟正确倒计时并循环
- 定时任务到时间触发通知
- 取消任务后不再触发
- 刷新页面后任务恢复调度
- 浏览器通知正确弹出
你学到了什么
Section titled “你学到了什么”- setTimeout/setInterval的精度限制 → Module: JavaScript事件循环
- 浏览器后台标签页的定时器节流 → Module: 浏览器API
- 简单调度器的数据结构设计 → Module: 任务调度基础
V2 — 10个用户:Go后端定时任务
Section titled “V2 — 10个用户:Go后端定时任务”番茄钟改为多用户版本,需要服务端定时任务:如每天8点发送今日任务提醒、每周生成统计报告。
你要解决什么
Section titled “你要解决什么”用Go实现后端定时任务调度器,支持cron表达式和goroutine执行。
给AI的Prompt
Section titled “给AI的Prompt”帮我用Go+Gin实现后端任务调度器:
1. Cron调度器: - 解析标准cron表达式(分 时 日 月 周) - 用time.Ticker驱动,每分钟检查一次是否有任务到期 - 任务到期时启动goroutine执行2. 内置任务: - 每天08:00:给所有用户发"今日待办"提醒 - 每周一09:00:生成上周统计报告 - 每小时:清理过期临时文件3. 管理API: - GET /api/tasks — 查看所有定时任务 - POST /api/tasks — 创建新任务(名称+cron表达式+handler) - DELETE /api/tasks/:id — 删除任务 - POST /api/tasks/:id/trigger — 手动触发一次4. 执行日志: - 内存中记录最近100次执行记录 - 记录:任务名、开始时间、耗时、状态(成功/失败)、错误信息5. 优雅停止: - 收到SIGTERM时等待正在执行的任务完成(最多30秒) - context取消机制
不要使用第三方cron库,自己实现cron表达式解析。- cron表达式正确触发任务
- 手动触发立即执行
- 执行日志记录完整
- 优雅关闭等待任务完成
- goroutine没有泄漏
你学到了什么
Section titled “你学到了什么”- Cron表达式语法和解析 → Module: 定时调度
- Go goroutine生命周期管理 → Module: Go并发
- 优雅关闭(graceful shutdown) → Module: 服务生命周期
V3 — 100个用户:持久化调度
Section titled “V3 — 100个用户:持久化调度”服务重启后所有定时任务丢失。需要任务持久化到数据库,重启后自动恢复。同时支持一次性定时任务。
你要解决什么
Section titled “你要解决什么”任务定义存数据库,服务启动时加载,支持周期任务和一次性任务。
给AI的Prompt
Section titled “给AI的Prompt”在V2基础上实现持久化任务调度:
1. 数据库模型(PostgreSQL): - scheduled_tasks表: id, name, type(cron/once), expression, handler_name, payload(JSON), next_run_at, last_run_at, status(active/paused/completed), retry_count, max_retries, created_at2. 任务类型: - 周期任务(cron):按cron表达式循环执行 - 一次性任务(once):指定时间执行一次,完成后标记completed - 延迟任务:N分钟/小时后执行(转换为一次性任务)3. 调度器逻辑: - 启动时从DB加载所有active任务 - 每30秒扫描一次next_run_at <= now的任务 - 执行后更新last_run_at,计算并更新next_run_at - 一次性任务执行后标记completed4. 失败重试: - 任务执行失败时retry_count+1 - 未超过max_retries则延迟重新调度(指数退避) - 超过max_retries标记为failed并告警5. API扩展: - POST /api/tasks/delay — 创建延迟任务("30分钟后提醒我") - GET /api/tasks/history — 执行历史(分页) - PUT /api/tasks/:id/pause — 暂停任务 - PUT /api/tasks/:id/resume — 恢复任务
handler_name映射到Go函数,用map[string]HandlerFunc注册。- 服务重启后任务自动恢复调度
- 一次性任务准时执行且只执行一次
- 失败任务按指数退避重试
- 暂停的任务不执行,恢复后继续
- 执行历史可分页查询
你学到了什么
Section titled “你学到了什么”- 任务调度的持久化设计 → Module: 持久化存储
- 指数退避重试策略 → Module: 容错模式
- 任务状态机(active→paused→completed→failed) → Module: 状态机设计
V4 — 1000个用户:分布式锁防重复
Section titled “V4 — 1000个用户:分布式锁防重复”服务部署了3个实例做负载均衡,定时任务被每个实例都执行了一次,导致用户收到3封重复邮件。
你要解决什么
Section titled “你要解决什么”用Redis分布式锁保证同一时刻只有一个实例执行某个定时任务。
给AI的Prompt
Section titled “给AI的Prompt”在V3基础上实现分布式任务调度:
1. Redis分布式锁: - 任务执行前获取锁:SET task_lock:{task_id} {instance_id} NX EX 300 - 获取到锁才执行,否则跳过 - 任务完成后释放锁(Lua脚本保证只释放自己的锁) - 锁超时时间 = 任务预期执行时间 * 22. 实例注册: - 每个实例启动时注册到Redis:instance:{id} → {ip, port, started_at} - 心跳续约,30秒过期3. 任务分配策略: - 方案A(抢占式):所有实例同时尝试获取锁,抢到的执行 - 方案B(分配式):按task_id % 实例数分配,只有被分配的实例尝试 - 默认用方案A(更简单),方案B作为优化选项4. 任务执行监控: - 记录哪个实例执行了哪个任务 - 检测任务执行超时(超过锁时间还没完成) - 超时任务告警5. 看门狗机制: - 长时间任务自动续约锁 - 每隔锁时间1/3续约一次 - 任务异常退出时锁自动过期释放
提供docker-compose.yml:3个服务实例 + Redis + PostgreSQL。- 3个实例只有1个执行了定时任务
- 执行实例宕机后锁自动过期,其他实例接管
- 看门狗正确续约长任务的锁
- 任务执行记录显示正确的实例ID
- 方案A和方案B都能正确工作
你学到了什么
Section titled “你学到了什么”- Redis分布式锁的正确实现(SET NX EX + Lua释放) → Module: 分布式锁
- 锁续约和看门狗机制(类Redisson) → Module: 锁的高级用法
- 分布式任务调度的核心难题 → Module: 分布式调度
V5 — 1万用户:DAG任务编排
Section titled “V5 — 1万用户:DAG任务编排”业务变复杂了:生成月报需要先统计用户数据、再汇总、再生成PDF、最后发邮件。这些步骤有先后依赖关系。
你要解决什么
Section titled “你要解决什么”实现DAG(有向无环图)任务编排,支持依赖调度、并行执行、失败重试。
给AI的Prompt
Section titled “给AI的Prompt”在V4基础上实现DAG任务编排:
1. DAG定义: - workflows表:id, name, dag_json, status, created_at - dag_json示例: { "nodes": ["统计数据", "生成汇总", "生成PDF", "发送邮件"], "edges": [["统计数据","生成汇总"], ["生成汇总","生成PDF"], ["生成PDF","发送邮件"]] } - 支持并行:如"统计用户"和"统计订单"可并行,"汇总"依赖二者2. DAG执行引擎: - 拓扑排序确定执行顺序 - 入度为0的节点可并行执行 - 节点完成后检查下游节点是否所有上游都完成 - 任何节点失败 → 整个workflow标记failed(可选继续)3. 节点执行: - 每个节点是一个handler函数 - 上游输出可作为下游输入(通过context传递) - 支持超时取消(单节点超时 + 整体超时)4. 失败处理: - 节点级重试(独立于workflow重试) - 从失败节点重跑(不重跑已成功的节点) - 手动跳过失败节点继续执行5. API: - POST /api/workflows — 创建workflow - POST /api/workflows/:id/run — 执行 - GET /api/workflows/:id/status — 查看执行状态(每个节点的状态) - POST /api/workflows/:id/retry — 从失败节点重试6. 可视化:返回DAG图的节点和边数据,前端可渲染
提供一个完整的"月报生成"workflow示例。- DAG拓扑排序正确
- 无依赖的节点并行执行
- 上游失败时下游不执行
- 从失败节点重试不重跑已成功节点
- 节点超时正确取消
你学到了什么
Section titled “你学到了什么”- DAG和拓扑排序 → Module: 图算法
- 任务编排的设计模式 → Module: 工作流引擎
- context在超时控制中的作用 → Module: Go context
V6 — 10万+用户:弹性调度平台
Section titled “V6 — 10万+用户:弹性调度平台”公司有大量定时任务和工作流,需要统一的调度平台。任务量波动大,需要弹性伸缩worker。
你要解决什么
Section titled “你要解决什么”构建弹性调度平台:动态worker池、优先级队列、延迟任务、完整监控。
给AI的Prompt
Section titled “给AI的Prompt”设计并实现弹性任务调度平台:
1. 架构分层: - Scheduler(调度器):负责任务触发和分配 - Queue(任务队列):Redis优先级队列 - Worker Pool(执行器池):可动态扩缩容 - Dashboard(监控面板):实时状态2. 优先级队列: - 使用Redis Sorted Set实现优先级队列 - 优先级:critical(0) > high(1) > normal(2) > low(3) - 同优先级按FIFO - 延迟任务:score = 执行时间戳,到时间才出队3. 动态Worker池: - Worker向Scheduler注册,汇报能力(CPU/内存/支持的任务类型) - Scheduler根据队列积压量动态调整Worker数量 - 伸缩策略:积压>100且持续1分钟 → 扩容;空闲5分钟 → 缩容 - Worker上限/下限可配置4. 任务路由: - 按任务类型路由到特定Worker(如GPU任务只给GPU Worker) - 按负载均衡分配 - 亲和性调度:相同数据的任务优先分配到同一Worker(缓存友好)5. 监控面板: - 实时数据:队列深度、各优先级任务数、Worker数和负载 - 历史趋势:任务执行量、平均耗时、失败率 - 告警:队列积压、Worker离线、任务失败率飙升6. 延迟任务: - 支持"30分钟后执行""每天早上8点执行" - 延迟任务存Redis ZSet,score=执行时间戳 - 到期扫描转移到执行队列
重点实现优先级队列和动态Worker池的伸缩逻辑。- critical任务总是优先执行
- 延迟任务准时进入执行队列
- 积压增加时Worker自动扩容
- 空闲时Worker自动缩容
- 监控面板实时显示队列和Worker状态
你学到了什么
Section titled “你学到了什么”- 优先级队列的实现(Redis Sorted Set) → Module: 数据结构应用
- 弹性伸缩策略设计 → Module: 自动扩缩容
- Worker Pool模式 → Module: 并发模型
- 调度系统的分层架构 → Module: 平台化思维