72 lines
1.6 KiB
Go
72 lines
1.6 KiB
Go
|
package runner
|
|||
|
|
|||
|
import (
|
|||
|
"errors"
|
|||
|
"os"
|
|||
|
"os/signal"
|
|||
|
"time"
|
|||
|
)
|
|||
|
|
|||
|
var ErrTimeOut = errors.New("执行者执行超时")
|
|||
|
var ErrInterrupt = errors.New("执行者被中断")
|
|||
|
|
|||
|
//一个执行者,可以执行任何任务,但是这些任务是限制完成的,
|
|||
|
//该执行者可以通过发送终止信号终止它
|
|||
|
type Runner struct {
|
|||
|
tasks []func(int) //要执行的任务
|
|||
|
complete chan error //用于通知任务全部完成
|
|||
|
timeout <-chan time.Time //这些任务在多久内完成
|
|||
|
interrupt chan os.Signal //可以控制强制终止的信号
|
|||
|
}
|
|||
|
|
|||
|
func NewRunner(tm time.Duration) *Runner {
|
|||
|
return &Runner{
|
|||
|
complete: make(chan error),
|
|||
|
timeout: time.After(tm),
|
|||
|
interrupt: make(chan os.Signal, 1),
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//将需要执行的任务,添加到Runner里
|
|||
|
func (r *Runner) Add(tasks ...func(int)) {
|
|||
|
r.tasks = append(r.tasks, tasks...)
|
|||
|
}
|
|||
|
|
|||
|
//执行任务,执行的过程中接收到中断信号时,返回中断错误
|
|||
|
//如果任务全部执行完,还没有接收到中断信号,则返回nil
|
|||
|
func (r *Runner) run() error {
|
|||
|
for id, task := range r.tasks {
|
|||
|
if r.isInterrupt() {
|
|||
|
return ErrInterrupt
|
|||
|
}
|
|||
|
task(id)
|
|||
|
}
|
|||
|
return nil
|
|||
|
}
|
|||
|
|
|||
|
//检查是否接收到了中断信号
|
|||
|
func (r *Runner) isInterrupt() bool {
|
|||
|
select {
|
|||
|
case <-r.interrupt:
|
|||
|
signal.Stop(r.interrupt)
|
|||
|
return true
|
|||
|
default:
|
|||
|
return false
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//开始执行所有任务,并且监视通道事件
|
|||
|
func (r *Runner) Start() error {
|
|||
|
//希望接收哪些系统信号
|
|||
|
signal.Notify(r.interrupt, os.Interrupt)
|
|||
|
go func() {
|
|||
|
r.complete <- r.run()
|
|||
|
}()
|
|||
|
select {
|
|||
|
case err := <-r.complete:
|
|||
|
return err
|
|||
|
case <-r.timeout:
|
|||
|
return ErrTimeOut
|
|||
|
}
|
|||
|
}
|