errgroup 实现 http server启动和关闭

errgroup 实现 http server启动和关闭,第1张

errgroup 实现 http server启动和关闭

文章目录 errgroup 实现 http server启动和关闭问题描述实现方案具体过程实现 http server 的启动和关闭使用 chan 实现对中断的注册和处理通过 errgroup + context 的形式 管理 goroutine最终的实现 小结References

问题描述

基于 errgroup 实现一个 http server 的启动和关闭 ,以及 linux signal 信号的注册和处理,要保证能够一个退出,全部注销退出。

实现方案

根据描述信息,可以简单汇总成3块内容:

实现 HTTP server 的启动和关闭监听 linux signal信号,支持 kill -9 或 Ctrl+C 的中断 *** 作 *** 作errgroup 实现多个 goroutine 的级联退出

按照实现方案,我们将任务拆分成多个小的功能。

实现 http server 的启动和关闭功能使用 chan 实现对 linux signal 中断的注册和处理通过 errgroup + context 的形式,对 1、2中的 goroutine 进行级联注销 具体过程 实现 http server 的启动和关闭

一般的http server 启动

func helloServer(w http.ResponseWriter, req *http.Request){
    io.WriteString(w,"hello,word!")
}
func main(){
    http.HandleFunc("/hello", helloServer)
    if err := http.ListenAndServer(":8080",nil); err!=nil{
        log.Fatal("server start error: ", err)
    }
}

http.ListenAndServer 其实最后调用的是 func (srv *Server) ListenAndServe() error {…},所以我们可以直接使用 srv *Server 来调用,代码如下

srv := &http.Server{Addr: ":9090"}
http.HandleFunc("/hello", HelloServer2)
fmt.Println("http server start")
if err := srv.ListenAndServer(); err!=nil{
	log.Fatal("server start error: ", err)
}
//关闭 server 
// srv.Shutdown(context.TODO())
使用 chan 实现对中断的注册和处理

通过 signal.Notify(…) 实现对中断信号量的监听,完整代码如下

func main(){
	c := make(chan os.Signal, 1)
	signal.Notify(c)	

	//block until a signal is received.
	s := <-c
	fmt.Println("Go signal:", s) // Got signla: terminal
}
通过 errgroup + context 的形式 管理 goroutine

errgroup 是借助 waitgroup、context 以及sync.Once 这3个组件实现的,可以把第一个出错的 goroutine 的错误信息传递出来。

Wait() 通过 waitgroup.Wait() 实现阻塞等待;WithContext() 通过 context.WithCancel(ctx), 设定返回的cancel 方法,来级联取消其他 child context 的goroutineGo() 通过 Once 实现执行一次 cancel() *** 作,并记录第一个出错信息

一个简单的demo

func main(){
    ctx := context.Backgorund()
    group, errCtx := errgroup.WithGroup(ctx)
    for index :=0; index<3; index++ {
        indexTemp := index;
        group.Go(func() err{
            time.Sleep(indexTemp * time.Second) 
            fmt.Printf("goroutine %d done!\n", indeTemp)
            if( indexTemp == 2){
                return errors.New(" index == 2")
            }
            return nil
        })    
    }

    if err := group.Wait(); err != nil{
        fmt.Println("done errors: ", err)
    }else{
        fmt.Println("all done successfully!")
    }
}
最终的实现
//启动 HTTP server
func StartHttpServer(srv *http.Server) error {
	http.HandleFunc("/hello", HelloServer2)
	fmt.Println("http server start")
	err := srv.ListenAndServe()
	return err
}

// 增加一个 HTTP hanlder
func HelloServer2(w http.ResponseWriter, req *http.Request) {
	io.WriteString(w, "hello, world!\n")
}

//1. 基于 errgroup 实现一个 http server 的启动和关闭 ,以及 linux signal 信号的注册和处理,要保证能够一个退出,全部注销退出。
func main() {
	ctx := context.Background()
	// 定义 withCancel -> cancel() 方法 去取消下游的 Context
	ctx, cancel := context.WithCancel(ctx)
	// 使用 errgroup 进行 goroutine 取消
	group, errCtx := errgroup.WithContext(ctx)
	//http server
	srv := &http.Server{Addr: ":9090"}

	group.Go(func() error {
		return StartHttpServer(srv)
	})

	group.Go(func() error {
		<-errCtx.Done() //阻塞。因为 cancel、timeout、deadline 都可能导致 Done 被 close
		fmt.Println("http server stop")
		return srv.Shutdown(errCtx) // 关闭 http server
	})

	chanel := make(chan os.Signal, 1) //这里要用 buffer 为1的 chan
	signal.Notify(chanel)

	group.Go(func() error {
		for {
			select {
			case <-errCtx.Done(): // 因为 cancel、timeout、deadline 都可能导致 Done 被 close
				return errCtx.Err()
			case <-chanel: // 因为 kill -9 或其他而终止
				cancel()
			}
		}
        return nil
	})

	if err := group.Wait(); err != nil {
		fmt.Println("group error: ", err)
	}
	fmt.Println("all group done!")

}
小结

基于 errgroup 实现一个 http server 的启动和关闭 ,以及 linux signal 信号的注册和处理,要保证能够一个退出,全部注销退出。

我们可以分析并定义好结束内容,以终为始,根据交付内容做好任务分解。这里我们分解成了3个小功能逐个击破:

实现 HTTP server 的启动和关闭监听 linux 的 signal信号,支持 kill -9 或 Ctrl+C 的中断 *** 作 *** 作errgroup 实现多个 goroutine 的级联退出

可以先从简单的Demo入手,学习使用 关键技术,然后最后拼装起来,打包要求的内容

References

https://blog.csdn.net/yzf279533105/article/details/97039688

https://studygolang.com/articles/32169?fr=sidebar

https://www.cnblogs.com/ricklz/p/14500392.html

https://www.jianshu.com/p/3e23e46f5a40

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/996409.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-21
下一篇 2022-05-21

发表评论

登录后才能评论

评论列表(0条)

保存