- Created by 郭强, last modified on Sep 27, 2022
基本介绍
gproc
组件提供了统一的信号监听和回调处理功能,目的是解决在程序中多个不同组件冗余的信号处理逻辑,以及接收退出信号后无法平滑析构的痛点。在没有统一退出信号监听的组件下,当多个组件通过goroutine
异步监听信号,主goroutine
接收到退出信号往往会直接退出,或者等待一段无法预测的时间退出,造成程序其实无法平滑退出,可能引起一些不可预料的问题。gproc
通过统一的信号注册和回调处理,使得各个组件能够有效地接收到退出信号并做相应析构处理,使得程序的信号处理逻辑更加严谨。
相关方法:
// AddSigHandler adds custom signal handler for custom one or more signals. func AddSigHandler(handler SigHandler, signals ...os.Signal) // AddSigHandlerShutdown adds custom signal handler for shutdown signals: // syscall.SIGINT, // syscall.SIGQUIT, // syscall.SIGKILL, // syscall.SIGTERM, // syscall.SIGABRT. func AddSigHandlerShutdown(handler ...SigHandler) // Listen blocks and does signal listening and handling. func Listen()
简要介绍:
AddSigHanlder
方法用于添加对指定信号的监听和对应回调函数注册。AddSigHandlerShutdown
方法用于添加对常见进程退出信号的监听和对应回调函数注册,可以注册多个SigHandler
。Listen
方法用于阻塞监听信号并自动执行回调函数调用。
我们来看两个示例。
示例1,使用标准库信号监听
使用标准库信号监听机制的常见代码逻辑如下:
package main import ( "fmt" "os" "os/signal" "syscall" "time" ) func signalHandlerForMQ() { var ( sig os.Signal receivedChan = make(chan os.Signal) ) signal.Notify( receivedChan, syscall.SIGINT, syscall.SIGQUIT, syscall.SIGKILL, syscall.SIGTERM, syscall.SIGABRT, ) for { sig = <-receivedChan fmt.Println("MQ is shutting down due to signal:", sig.String()) time.Sleep(time.Second) fmt.Println("MQ is shut down smoothly") return } } func main() { fmt.Println("Process start, pid:", os.Getpid()) go signalHandlerForMQ() var ( sig os.Signal receivedChan = make(chan os.Signal) ) signal.Notify( receivedChan, syscall.SIGINT, syscall.SIGQUIT, syscall.SIGKILL, syscall.SIGTERM, syscall.SIGABRT, ) for { sig = <-receivedChan fmt.Println("MainProcess is shutting down due to signal:", sig.String()) return } }
我们通过go run
命令来执行一下,随后通过Ctrl+C
快捷键退出(Mac
用户通过Command+C
)。
$ go run signal_handler.go Process start, pid: 21928 ^CMainProcess is shutting down due to signal: interrupt MQ is shutting down due to signal: interrupt
可以看到,好可惜,那个MQ
的goroutine
还没完全退出进程即被强行关闭。
示例2,使用gproc
信号监听
使用gproc
组件改进后的信号监听机制如下:
package main import ( "fmt" "github.com/gogf/gf/v2/os/gproc" "os" "time" ) func signalHandlerForMQ(sig os.Signal) { fmt.Println("MQ is shutting down due to signal:", sig.String()) time.Sleep(time.Second) fmt.Println("MQ is shut down smoothly") } func signalHandlerForMain(sig os.Signal) { fmt.Println("MainProcess is shutting down due to signal:", sig.String()) } func main() { fmt.Println("Process start, pid:", os.Getpid()) gproc.AddSigHandlerShutdown( signalHandlerForMQ, signalHandlerForMain, ) gproc.Listen() }
我们通过go run
命令来执行一下,随后通过Ctrl+C
快捷键退出(Mac
用户通过Command+C
)。
$ go run signal_handler_gproc.go Process start, pid: 22876 ^CMQ is shutting down due to signal: interrupt MainProcess is shutting down due to signal: interrupt MQ is shut down smoothly
看到差别了吧!所有的信号监听函数都正常结束后,随后进程平滑退出。
Content Menu
- No labels
1 Comment
harbor
贡献一个,跟goframe web框架融合的方式,在cmd.go 中,server 的Run方法之前,启动一个协程即可