# 任务机制 任务机制贯穿整个项目,在/pkg/task 目录下定义。任何逻辑在设计时,必须先考虑使用任务机制来实现,这样可以保证被观测,也可以捕获 panic 等等。 ## 概念定义 ### 继承 任务机制中,所有任务都是通过继承来实现的。 go语言没有继承,但可以通过嵌入来实现。 ### 宏任务 宏任务又叫父任务,可以包含多个子任务的执行,本身也是一个任务。 ### 子任务协程 每一个宏任务都会启动一个协程,用来执行子任务的 Start、 Run、 Dispose 方法。因此,拥有同一个父任务的子任务,可以避免并发执行问题。这个协程可能不会一开始就创建,也就是可能会是懒加载。 ## 任务的定义 任务通常通过继承 `task.Task` 、`task.Job` 、`task.Work` 、`task.ChannelTask` 、 `task.TickTask` 来定义。 例如: ```go type MyTask struct { task.Task } ``` - `task.Task` 是所有任务的基类,定义了任务的基本属性和方法。 - `task.Job` 可包含子任务,子任务全部结束后,Job 会结束。 - `task.Work` 同 Job,但子任务结束后,Work 会继续执行。 - `task.ChannelTask` 自定义信号的任务,通过 覆盖 `GetSignal` 方法来实现。 - `task.TickTask` 定时任务,继承自 `task.ChannelTask` ,通过 覆盖 `GetTickInterval` 方法来控制定时器间隔。 ### 定义任务启动方法 通过定义一个方法 Start() error 来实现任务的启动。 其中返回的 error 可以用来判断任务是否启动成功。如果为空则代表任务成功启动了。否则代表启动失败(特殊情况,返回 Complete 代表任务完成)。 通常在 Start 中包含资源的创建,例如打开文件,建立网络连接等。 Start 方法是可选的,如果没有定义,则默认启动成功。 ### 定义任务的执行过程 通过定义一个方法 Run() error 来实现任务的执行过程。 这个方法通常用来执行耗时操作,同时会阻塞父任务的子任务协程。 还有一个非阻塞的方式来运行耗时操作,就是定义 Go() error 方法。 error 返回的值如果是 nil 则代表任务执行成功,否则代表执行失败(特殊情况,返回 Complete 代表任务完成)。 Run 和 Go 也是可选的,如果不定义则任务会处于正在运行状态。 ### 定义任务的销毁过程 通过定义一个方法 Dispose() 来实现任务的销毁过程。 这个方法通常用来释放资源,例如关闭文件,关闭网络连接等。 Dispose 方法也是可选的,如果没有定义,则任务结束不做任何操作。 ## 钩子机制 通过 OnStart、OnBeforeDispose、OnDispose 方法来实现钩子机制。 ## 等待任务开始和结束 通过 WaitStarted() 和 WaitStopped() 方法来实现等待任务开始和结束。这种方式会阻塞当前协程。 ## 重试机制 通过设置 Task 的 RetryCount 和 RetryInterval 来实现重试机制。有一个设置方法,SetRetry(maxRetry int, retryInterval time.Duration)。 ### 触发条件 - 当 Start 失败时,会重试调用 Start 直到成功。 - 当 Run 或者 Go 失败时,则会先调用 Dispose 释放资源后再调用 Start 开启重试流程。 ### 终止条件 - 当重试次数满了之后就不再重试了。 - 当 Start 或者 Run、Go 返回 ErrStopByUser 、 ErrExit 、ErrTaskComplete 时,则终止重试。 ## 启动一个任务 通过调用父任务的 AddTask 方法来启动一个任务。 不可以直接主动调用任务的 Start 方法。Start 方法必须是被父任务调用。 ## 任务的停止 通过调用 Stop(err error) 方法来实现任务的停止。err 不能传入 nil。定义任务时不要覆盖 Stop 方法。 ## 任务的停止原因 通过调用 StopReason() 方法可以检查任务的停止原因。 ## Call 方法 调用 Job 的 Call 会创建一个临时任务,用来在子任务协程中执行一个函数,通常用来访问 map 等需要防止并发读写的资源。由于该函数会在子任务协程中运行,因此不可以调用 WaitStarted 和 WaitStopped 以及其他阻塞协程的逻辑,否则会导致死锁。