英文:
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
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论