Go 1.23 · 零第三方依赖 · MIT

让每一个任务
都有始有终

GoTask 是 Go 的进程内任务生命周期内核。用「任务树 + 单协程事件循环」统一管理组件的启动、运行、停止、重试、资源回收与观测——像操作系统任务管理器一样,精确控制任意粒度的逻辑。

$ go get github.com/langhuihui/gotask
✓ 一切皆任务 ✓ 协作式优雅关闭 ✓ 七态可观测
reflect.Select × 3
state: RUNNING
retry 1 / 3
RootManager task tree root · OS signal Job · EventLoop 1 goroutine · dynamic cases HTTP Server RUNNING Run() 阻塞 Data Pipeline GOING Go() 独立协程 Ticker CHANNEL Tick(any) Stop(reason) → Context 取消 → 子任务自底向上回收
向下探索原理
0第三方依赖仅标准库
7生命周期状态atomic 状态机
1协程 / 每个 Job顺序执行无锁
65535case 上限保护reflect.Select 硬限制
01 / WHY GOTASK

复杂项目里,难的不是「跑起来」
而是「停得干净」

goroutine 可以随手写,但谁创建、归谁管、何时算启动成功、失败后是否重跑、资源由谁释放——这些问题的答案,决定了系统在压力下的样子。

每个任务同时是 生命周期对象 树节点 context.Context 可观测对象
01

可观测性

任务树、唯一 ID、启动/停止原因、重试次数与调用点文件行号,让执行路径不再靠猜。

02

并发安全

子任务的 Start / Run / Dispose 与 Job.Call 闭包,都在父任务唯一协程内顺序执行。

03

资源销毁

分阶段清理顺序、自动级联销毁、关联销毁与竞态安全,解决异步系统最棘手的一题。

04

系统稳定性

优雅关闭、指数退避重试、panic 兜底与钩子代际护栏,让异常路径也有确定性。

02 / INTERACTIVE LAB

把原理放慢看一遍

四段可交互动画,逐步演示 GoTask 的调度内核、状态机、级联销毁与重试策略。可自动播放,也可单步查看每一步对应的源码位置。

单协程事件循环 · 一次任务的完整旅程

任意 goroutine 提交任务 → 输入通道 → 动态 reflect.Select 调度 → 启动 / 重试 / 回收 → 自动休眠。

业务 goroutine
job.AddTask(t) t · *Worker

任意协程可安全提交

Input Channel case 0

buffer 256 · 满则 ErrTooManyChildren

父 Job 的唯一协程
EventLoop.run()idle
reflect.Select(cases)
case 0 · input chan
等待事件…
子任务
暂无子任务
03 / CAPABILITIES

一套内核,覆盖整个生命周期

以下能力均来自核心库实现,而非概念承诺。

动态 reflect.Select

运行时增减 case,突破 Go 静态 select 限制;删除用 swap-delete,65535 上限与输入通道背压双重保护。

event_loop.go

单协程事件循环

Start / Run / Dispose 与 Job.Call 闭包都在父任务唯一协程内串行执行,共享状态无需加锁。

Job.Call

任务树与级联销毁

按业务 Key 去重;父任务停止时逐个 Stop 子任务并等待 shutdown,Work 容器可持续长驻。

job.go

分阶段资源回收

PreDispose → 等待子任务 → Dispose → resources → OnDispose;io.Closer、Recyclable 与关联任务自动释放。

task.go · dispose()

生命周期钩子

OnStart / OnDispose / OnStop / Using;晚注册补跑队列与 hookGen 代际护栏,杜绝钩子丢失与重试串台。

hookGen

可选重试策略

SetRetry 指数退避、MaxRetryInterval 封顶、-1 无限重试;ErrTaskComplete / ErrExit 等停止原因立即收敛。

checkRetry()

泛型强类型编排

TaskFunc[T] 与 Then / Map / Chain、Parallel / ParallelMap、WithRetry / WithTimeout,增量接入且无 breaking change。

generic.go

可观测与兜底

ID、StartReason、StopReason、RetryCount、slog 结构化日志;四处 recover 兜底,-tags taskpanic 切换调试直抛。

stability
04 / GET STARTED

三分钟,把任务托付给树

用 RootManager 作为根,任务只需实现自己关心的钩子方法。

// 一切皆任务:嵌入 task.Task,按需实现生命周期方法
package main

import (
    "time"

    "github.com/langhuihui/gotask"
)

type Worker struct {
    task.Task
}

func (w *Worker) Start() error {
    w.Info("worker ready")
    return nil
}

func (w *Worker) Run() error {
    <-w.Done()   // 协作式停止:Context 被取消时退出
    return nil
}

func (w *Worker) Dispose() {
    w.Info("worker disposed")
}

type Manager = task.RootManager[uint32, *Worker]

func main() {
    root := &Manager{}
    root.Init()          // 注册 OS 信号,建立任务树根

    worker := &Worker{}
    root.AddTask(worker)   // 由父任务启动,勿直接调 Start()

    worker.WaitStopped()
}
05 / OBSERVABILITY

任务树,看得见

核心库提供后代事件广播与可观测字段;示例 Dashboard 用 OnDescendantsDispose 把历史写入 SQLite 并可视化。

localhost:8082 · GoTask 任务管理系统
GoTask Dashboard 任务树界面截图,展示任务 ID、类型、状态、运行与重试次数
01

实时任务树

Owner、状态、层级、启动时间、重试次数与发起程序调用点。

02

停止与重启

面板直接对指定任务调用停止 / 重启,验证生命周期控制粒度。

03

历史与甘特

按 ownerType、taskType、sessionId、parentId 与时间范围筛选分页查询。

04

一键启动

./dashboard/start.sh 构建前端并托管,后端 Go + SQLite,前端 React + TypeScript。

06 / POSITIONING

说清楚边界,才谈得上可靠

GoTask 不是分布式任务队列,也不假装是操作系统。它解决的是单个 Go 进程内的组件生命周期问题。

GoTask 擅长

  • 服务内任务树与父子关系建模
  • 协作式停止、优雅关闭与资源回收
  • 失败重试、panic 兜底与可观测性
  • 把散落的 goroutine 收进统一治理模型

需要明确的能力边界

  • Stop() 只取消 Context,无法强杀忽略信号的 goroutine
  • 无任务级内存 / 故障隔离,无精确 CPU 配额与硬实时
  • 无透明热替换代码;持久化队列请选 asynq / river
  • 历史落库由 Dashboard 示例实现,非核心库内置

若把目标定义为「在单进程内模拟具有强杀、强隔离、精确资源控制的操作系统」,那是 Go 运行时与地址空间模型的硬边界;需要强杀时,应把任务放入独立进程交由 supervisor 管理。

READY TO BUILD

把混乱的 goroutine
收进一棵任务树

零第三方依赖、MIT 协议、中英双语文档与 10 课渐进式教程。

前往 GitHub
$ go get github.com/langhuihui/gotask