当前位置: 首页 > news >正文

Go 安全使用goroutine

Go 安全使用goroutine

go 正常使用goroutine开启一个携程很简单

var a int
go func(){a=1+1
}()

这么用在日常工具什么的开发中肯定没问题,如果携程内有问题崩掉了,使用工具的人可以马上获得堆栈信息将其反应给开发人员。但是你如果在web服务器或者后台程序中使用就有大问题。因为golang无法捕获携程中的panic,也就是说你携程崩掉了,你携程中又没有recover,你整个程序都会被其带崩,并且崩溃是父携程不可捕获的。

上案例

package mainimport ("net/http""github.com/gin-gonic/gin"
)func main() {app := gin.New()app.Handle(http.MethodGet, "/panic", func(ctx *gin.Context) {go func() { panic("goroutine panic") }()})app.Handle(http.MethodPost, "/panic", func(ctx *gin.Context) { panic("panic") })http.ListenAndServe("0.0.0.0:7999", app)
}

此处使用gin框架做示范,模拟了两种崩溃情况.此时分别以get和post两种方法请求/panic接口,get请求程序,程序会因为无法捕获携程中的panic会崩溃,而post请求会恢复,因为golang 处理http请求时,在携程中使用了recover,你只要用http.ListenAndServe就能保你。但是你如果再自己的handlefunc 中再开子携程且没有上保护措施那么就保不住你啰
请添加图片描述

编写一个安全的goroutine 构建器

type Trace struct {info  anystack string
}
type RoutineBuilder struct {out       io.WritertraceChan chan Trace
}func (rb *RoutineBuilder) Go(fun func()) {go func(f func()) {defer func() {//记录panic原因,以及堆栈信息用于排查if r := recover(); r != nil {rb.traceChan <- Trace{info:  r,stack: string(debug.Stack()),}}}()f()}(fun)
}
func NewRoutineBuilder(out io.Writer) (*RoutineBuilder, <-chan Trace) {var rb = RoutineBuilder{out:       out,traceChan: make(chan Trace, 20),}return &rb, rb.traceChan
}

应用该携程构建器到案例中

这里的策略为将意外崩溃的携程信息直接写到标准输出,日志处理那步可以根据自身需求对堆栈信息做处理

package mainimport ("fmt""io""net/http""os""runtime/debug""time""github.com/gin-gonic/gin"
)type Trace struct {info  anystack string
}
type RoutineBuilder struct {out       io.WritertraceChan chan Trace
}func (rb *RoutineBuilder) Go(fun func()) {go func(f func()) {defer func() {if r := recover(); r != nil {rb.traceChan <- Trace{info:  r,stack: string(debug.Stack()),}}}()f()}(fun)
}
func NewRoutineBuilder(out io.Writer) (*RoutineBuilder, <-chan Trace) {var rb = RoutineBuilder{out:       out,traceChan: make(chan Trace, 20),}return &rb, rb.traceChan
}var routineBuilder, stackChan = NewRoutineBuilder(os.Stderr)
//记录意外崩溃的堆栈信息和原因到日志中
func traceLogCheck() {defer func() {if r := recover(); r != nil {fmt.Fprintln(routineBuilder.out, time.Now(), " trace log check panic", r, string(debug.Stack()))traceLogCheck()}}()for info := range stackChan {fmt.Fprintln(routineBuilder.out, time.Now(), " trace log check panic", info.info, info.stack)}
}
func init() {go traceLogCheck()
}
func main() {app := gin.New()app.Handle(http.MethodGet, "/panic", func(ctx *gin.Context) {routineBuilder.Go(func() { panic("goroutine panic") })})app.Handle(http.MethodPost, "panic", func(ctx *gin.Context) { panic("panic") })http.ListenAndServe("0.0.0.0:7999", app)
}

看看效果

成功拦截到handfunc中子携程的panic
在这里插入图片描述


http://www.mrgr.cn/news/11307.html

相关文章:

  • 浪潮服务器主板集成RAID常见问题
  • C++核心编程02——引用
  • 分享一个基于Python的广东热门旅游数据可视化分析系统flask毕设(源码、调试、LW、开题、PPT)
  • Linux shell编程学习笔记75:sed命令——沧海横流任我行(下)
  • 基于单片机的程控电源显示控制电路设计
  • 100101-批量将指定文件夹下视频时长快进或慢放到指定时长,指定比例尺寸,例如将50S视频转为1:1尺寸的30S-UI
  • spring security怎么生成JWT返回前端,以及怎么自定义JWT认证过滤器
  • Qt WebSocket
  • Vue3学习——Node环境安装(一)
  • 扫描件转word如何操作?分享3个转换技巧,简单高效
  • OpenLDN
  • GIMP简单应用: 将图片输出为指定分辨率
  • 浅谈【数据结构】图-图的概念
  • LVS部署——DR集群
  • C++中常见的数据结构
  • Physics of Language Models学习小结
  • Java中等题-整数拆分(力扣)
  • 趣味算法------猴子吃桃(循环,递归双重解法)
  • java一键生成数据库说明文档html格式
  • 【Python机器学习】NLP概述——深度处理