英文:
How to intercept `runtime.Goexit()` signal
问题
package main
import (
	"fmt"
	"path"
	"runtime"
	"strconv"
	"time"
	"github.com/fatih/color"
	"github.com/gin-gonic/gin"
)
var (
	Errors map[string]string
	err    error
)
func CheckErr(err error) {
	if err != nil {
		pc, file, line, _ := runtime.Caller(1)
		color.New(color.FgRed).PrintfFunc()(" [app]")
		color.New(color.FgMagenta).PrintfFunc()(fmt.Sprintf("%v:", time.Now().Format("15:04:05.00000")))
		color.New(color.FgGreen).PrintfFunc()(fmt.Sprintf("%v] %v:%v:", path.Ext(runtime.FuncForPC(pc).Name())[1:], path.Base(file), line))
		color.Yellow(" %v", err)
		Errors["app "+time.Now().Format("15:04:05.00000")+" "+path.Ext(runtime.FuncForPC(pc).Name())[1:]+" "+path.Base(file)+":"+strconv.Itoa(line)] = err.Error()
		runtime.Goexit()
	}
}
func test(hello string) (string, error) {
	// ...
	if err != nil {
		return "", err
	}
	text := hello + " world"
	return text, nil
}
func main() {
	router := gin.Default()
	router.POST("/hello", func(context *gin.Context) {
		message, err := test("hello")
		if err != nil {
			CheckErr(err)
		}
		context.JSON(200, gin.H{
			"message": message,
			"Errors":  Errors,
		})
	})
	router.Run(":8080")
}
CheckErr是一个收集错误日志、打印错误并退出的函数main是一个 gin 服务test是 gin 的数据获取函数- 由于 
test需要返回数据,所以不能使用go协程 
> 当 test 失败时,我如何返回到 gin 并返回错误消息?
英文:
package main
import 	(
	"github.com/fatih/color"
	"github.com/gin-gonic/gin"
	"runtime"
)
var (
	Errors map[string]string
	err error
)
func CheckErr(err error) {
	if err != nil {
		pc, file, line, _ := runtime.Caller(1)
		color.New(color.FgRed).PrintfFunc()(" [app]")
		color.New(color.FgMagenta).PrintfFunc()("%v:", time.Now().Format("15:04:05.00000"))
		color.New(color.FgGreen).PrintfFunc()("%v] %v:%v:", path.Ext(runtime.FuncForPC(pc).Name())[1:], path.Base(file), line)
		color.Yellow(" %v", err)
		Errors["app "+time.Now().Format("15:04:05.00000")+" "+path.Ext(runtime.FuncForPC(pc).Name())[1:]+" "+path.Base(file)+":"+strconv.Itoa(line)] = err.Error()
		runtime.Goexit()
	}
}
func test(hello string) string{
	// ...
	if err!=nil{
		CheckErr(err)
	} 
	text := hello+" world"
	return test
}
func main() {
	req.POST("/hello", func(context *gin.Context) {
		message:=test("hello")
		context.JSON(200, gin.H{
			"message": message,
			"Errors": Errors,
		})
	}
}
- CheckErr is a function that collects error logs, prints errors and exits
 - main is a gin service
 - test is the data acquisition function of gin
 - Cannot use 
gocoroutine becausetestneeds to return data 
> How can I go back to gin and return the error message when test fails?
答案1
得分: 2
如果你坚持使用runtime.Goexit(),那么你必须使用另一个goroutine。结合使用chan或者sync.WaitGroup,它可以正常工作,因为Goexit会运行所有的延迟调用。
// Goexit在终止goroutine之前运行所有的延迟调用。因为Goexit不是panic,所以在这些延迟函数中的任何recover调用都将返回nil。
func CheckErr(err error, done chan struct{}) {
	defer func() { done <- struct{}{} }()
	if err != nil {
		// ...
		runtime.Goexit()
	}
}
func test(hello string) string {
	// ...
	if err != nil {
		done := make(chan struct{})
		go CheckErr(err, done)
		<-done
	}
	text := hello + " world"
	return text
}
英文:
If you insist on using runtime.Goexit() then you have to use another goroutine. Together with chan or sync.WaitGroup it works just fine since goexit runs all deferred calls.
> // Goexit runs all deferred calls before terminating the goroutine. Because Goexit
// is not a panic, any recover calls in those deferred functions will return nil.
func CheckErr(err error, done chan struct{}) {
defer func() { done <- struct{}{} }()
if err != nil {
// ...
runtime.Goexit()
}
}
func test(hello string) string {
// ...
if err != nil {
done := make(chan struct{})
go CheckErr(err, done)
<-done
}
text := hello + " world"
return text
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论