Go 安全使用goroutine

Go 安全使用goroutine

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

go 复制代码
var a int
go func(){
	a=1+1
}()

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

上案例

go 复制代码
package main

import (
	"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 构建器

go 复制代码
type Trace struct {
	info  any
	stack string
}
type RoutineBuilder struct {
	out       io.Writer
	traceChan 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
}

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

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

go 复制代码
package main

import (
	"fmt"
	"io"
	"net/http"
	"os"
	"runtime/debug"
	"time"

	"github.com/gin-gonic/gin"
)

type Trace struct {
	info  any
	stack string
}
type RoutineBuilder struct {
	out       io.Writer
	traceChan 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

相关推荐
笨鸟先飞,勤能补拙1 小时前
AI 赋能网络安全:技术全景、成熟度评估与实战案例
人工智能·python·安全·web安全·网络安全·sqlite·github
微学AI1 小时前
一根针指向所有方向:挂谷猜想对 LLM Agent 技能-记忆架构的启示
开发语言·人工智能·架构·挂谷猜想
豆瓣鸡2 小时前
算法日记 - Day3
java·开发语言·算法
Achou.Wang2 小时前
深入理解go语言-第5章 并发编程——Go的灵魂
大数据·算法·golang
韭菜炒鸡肝天3 小时前
VTK开发笔记(一):VTK介绍,Qt..+VSx+VTK.编译
开发语言·笔记·qt
Aaron - Wistron3 小时前
Web API C# (Furion版)带 单元测试
开发语言·后端·c#
笨鸟先飞,勤能补拙3 小时前
AI 赋能网络安全领域深度剖析
网络·人工智能·windows·安全·web安全·网络安全·github
HackTwoHub4 小时前
轻量化AI渗透武器库|ARTEX自主攻防系统、资产梳理、漏洞挖掘、链路分析全流程智能化落地
人工智能·安全·web安全·网络安全·系统安全·网络攻击模型·安全架构
Dxy12393102164 小时前
Python项目打包成EXE完整教程(PyInstaller实战避坑)
开发语言·python
0566465 小时前
Python康复训练——常用标准库
开发语言·python·学习