前言:看源码遇到了一个监督树的概念,好好探索一番
什么是监督树
我觉得监控树就是一种以树的形式管理多个进程/线程/协程(后面统一说进程)的程序设计模型。这一种模型基于 worker 和 supervisor 的思想。
- worker 就是用于工作的进程。
- supervisor 就是用于监控 worker 的进程。supervisor 在某一个 worker 出问题的时候可以重新启动 worker。
典型的 Supervision Tree 如下图所示(图片来自这里):
方框代表着 supervisor
圆框代表着 worker
1 表示 one_for_one
a 表示 one_for_all
one_for_one vs one_for_all
前者表示 worker failed 的时候,它的 supervisor 只重启这一个 worker。适用于在同一层的 worker 互不依赖的情况。
后者表示 worker failed 的时候,它的 supervisor 重启这一层的所有 worker。适用于同一层的 worker 互相依赖的情况。
在 Go 中如何应用
Supervision Tree 本是 Erlang 中的一个重要概念,但是有大佬把他移植到了 Go 上:https://github.com/thejerf/suture。
从 https://pkg.go.dev/github.com/thejerf/suture/v4 这上面可以看到具体怎么使用。
具体用法
package main
import (
"context"
"errors"
"fmt"
"github.com/thejerf/suture/v4"
"time"
)
type SimpleServer struct {
Name string
Time time.Duration
}
func (s *SimpleServer) Serve(ctx context.Context) error {
for {
fmt.Println(s.Name)
time.Sleep(s.Time)
}
}
type ReturnErrorServer struct {
}
func (s *ReturnErrorServer) Serve(ctx context.Context) error {
return errors.New("some stupid error")
}
type PanicServer struct {
}
func (s *PanicServer) Serve(ctx context.Context) error {
panic("panic")
return nil
}
func main() {
ctx := context.TODO()
r := suture.New("root", suture.Spec{})
s1 := &SimpleServer{"s1", time.Second}
s2 := &ReturnErrorServer{}
s3 := &PanicServer{}
r.Add(s1)
r.Add(s2)
r.Add(s3)
_ = r.Serve(ctx)
}
可以看到不断输出 s1,supervsior 会尝试重启 s2 s3 一定次数。