当前位置: 首页 > 科技观察

Go1.16的新函数Signal.NotifyContext如何使用?

时间:2023-03-14 15:35:17 科技观察

大家好,我是polarisxu。您可能不会经常使用os/signal包。但是从Go1.8开始,就有人开始使用这个包了,因为Go1.8在net/http包中增加了一个新的方法:func(srv*Server)Shutdown(ctxcontext.Context)errorwithit,youdon't需要借助第三方库,优雅关闭服务。怎么做?funcmain(){server=http.Server{Addr:":8080",}http.HandleFunc("/",func(whttp.ResponseWriter,r*http.Request){time.Sleep(time.Second*10)fmt.Fprint(w,"Helloworld!")})goserver.ListenAndServe()//监听中断信号(CTRL+C)c:=make(chanos.Signal,1)signal.Notify(c,os.Interrupt)<-c//重置os.Interrupt的默认行为signal.Reset(os.Interrupt)fmt.Println("shuttingdowngracefully,pressCtrl+Cagaintoforce")//给程序最多5秒的时间来处理正在服务的请求timeoutCtx,cancel:=context.WithTimeout(context.Background(),5*time.Second)defercancel()iferr:=server.Shutdown(timeoutCtx);err!=nil{fmt.Println(err)}}这里使用os/信号包监听中断信号;收到信号后,第16行<-c会返回;为了使用CTRL+C再次强制退出,通过Reset恢复os.Interrupt的默认行为;(这个不是必须的)优雅退出的关键:1)新的请求不能进来;2)现有请求将及时处理。因此,在收到信号后,调用server.Shutdown方法,阻止新的请求进来,同时给出5秒的等待时间,让进来的请求有时间处理。在Go1.16中,os/signal包增加了一个函数:funcNotifyContext(parentcontext.Context,signals...os.Signal)(ctxcontext.Context,stopcontext.CancelFunc)函数和Notify类似,只是用法有些不同。上面的示例使用NotifyContext代替:funcafter(){server=http.Server{Addr:":8080",}http.HandleFunc("/",func(whttp.ResponseWriter,r*http.Request){time.Sleep(time.Second*10)fmt.Fprint(w,"Helloworld!")})goserver.ListenAndServe()//监听中断信号(CTRL+C)ctx,stop:=signal.NotifyContext(context.Background(),os.Interrupt)<-ctx.Done()//重置os.Interrupt的默认行为,类似于signal.Resetstop()fmt.Println("shuttingdowngracefully,pressCtrl+Cagaintoforce")//给程序最多5秒的时间处理服务请求timeoutCtx,cancel:=context.WithTimeout(context.Background(),5*time.Second)defercancel()iferr:=server.Shutdown(timeoutCtx);err!=nil{fmt.Println(err)}}和上面的写法不同,但是功能是一样的。其实NotifyContext内部是基于Notify实现的:=&signalCtx{Context:ctx,cancel:cancel,signals:signals,}c.ch=make(chanos.Signal,1)Notify(c.ch,c.signals...)ifctx.Err()==nil{gofunc(){select{case<-c.ch:c.cancel()case<-c.Done():}}()}returnc,c.stop}只会在返回的stop时执行os/signal包称为中的Stop函数,这个Stop函数的作用和Reset类似。所以上面Notify的例子中,Reset的地方可以改成Stop。在封装方面,NotifyContext做得更好。而且,如果某些场景需要使用Context,它可以通过监听系统信号,一步创建Context。NotifyContext的用法和优雅关闭服务你掌握了吗?希望大家可以实际尝试一下,启动服务,通过curlhttp://localhost:8080/访问,按CTRL+C查看具体效果。只看不做,基础知识不是你的。关于NotifyContext函数的文档可以在这里查看:https://docs.studygolang.com/pkg/os/signal/#NotifyContext。本文转载自微信公众号「polarisxu」,可通过以下二维码关注。转载本文请联系polarisxu公众号。