在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
前情回顾前文我们完成了如下功能 本节目标我们旨在编写一个健壮性较强的日志监控系统,不得不考虑这样一个问题,当某个日志监控协程崩溃或者异常退出,该如何处理? 借尸还魂,增加异常处理我们在tailf.go的WatchLogFile中增加异常处理,在协程崩溃时打印日志信息,并且向keychan中写入字符串通知主协程处理。 func WatchLogFile(pathkey string, datapath string, ctx context.Context, keychan chan<- string) { //省略之前写好的逻辑 //.... defer func() { if errcover := recover(); errcover != nil { fmt.Println("goroutine watch ", pathkey, " panic") fmt.Println(errcover) keychan <- pathkey } }() //省略逻辑.... } WatchLogFile函数进行了扩充,增加了pathkey字符串表示监控哪个日志文件,pathkey实际是config.yaml中的路径的key值。 主协程中增加复活逻辑同样,在主协程中我们需要创建keychan这个缓冲chan,并且捕获子协程发过来的崩溃消息。 func main(){ //....省略 keyChan := make(chan string, KEYCHANSIZE) //.... for { select { case pathData, ok := <-pathChan: //省略... case keystr := <-keyChan: val, ok := configMgr[keystr] if !ok { continue } fmt.Println("recover goroutine watch ", keystr) var ctxcover context.Context ctxcover, val.ConfigCancel = context.WithCancel(context.Background()) go logtailf.WatchLogFile(keystr, val.ConfigValue, ctxcover, keyChan) } } } 在主协程中愿有逻辑基础上,我们增加了keyChan的初始化,以及keychan数据的监听。 keychan该如何回收keychan被多个子协程引用,该如何回收?这种情况下多个子协程写数据,一个主协程接受数据,我们常用的策略如下: 制造协程崩溃现场,模拟测试系统稳定性为了测试我们的系统稳定性,我在修改WatchLogFile函数,新增如下处理,中断key值为logdir3的监控协程,进而观察主协程能否再次启动协程监听该日志文件。 func WatchLogFile(pathkey string, datapath string, ctx context.Context, keychan chan<- string) { //...省略 defer func() { if errcover := recover(); errcover != nil { fmt.Println("goroutine watch ", pathkey, " panic") fmt.Println(errcover) keychan <- pathkey } }() //模拟崩溃 if pathkey == "logdir3" { panic("test panic ") } //...省略 然后我们启动日志系统,看到如下效果
从日志上可以看到每当我们的协程挂掉,主协程会启动新的协程继续监听日志,保证了系统的稳定性。
|
请发表评论