golang的平滑关闭

最近在看公司的一个go项目,发现一段有意思的代码,代码大致的结构如下:

func main() {
	engine := gin.Default()
	engine.Handle("GET", "/hello", func(context *gin.Context) {
		context.JSON(http.StatusOK, gin.H{
			"err":  0,
			"data": []string{},
		})
		time.Sleep(5 * time.Second)
	})

	server := http.Server{
		Addr:    ":8081",
		Handler: engine,
	}

	go func() {
		c := make(chan os.Signal)
		signal.Notify(c, syscall.SIGINT, syscall.SIGTERM)
		<-c
		ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
		err := server.Shutdown(ctx)
		if err != nil {
			cancel()
		}
	}()

	err := server.ListenAndServe()
	if err == nil {
		fmt.Println("error")
	}
}

  在这段代码中,使用子协程去监听关闭通知。这显然是不能达到代码写者想要达到的效果的。原因在于当主协程收到退出信号时会直接退出,而没有去关注子协程的状态,而在go语言中,主协程一旦退出,子协程也就退出了,所以并不能达到平滑关闭的效果。

  如果要达到平滑关闭的效果:

    方法一:需要将ListenAndServe放到子协程中,而在主协程中监听退出信号。

func main() {
	engine := gin.Default()
	engine.Handle("GET", "/hello", func(context *gin.Context) {
		context.JSON(http.StatusOK, gin.H{
			"err":  0,
			"data": []string{},
		})
		time.Sleep(5 * time.Second)
	})

	server := http.Server{
		Addr:    ":8081",
		Handler: engine,
	}

	go func() {
		err := server.ListenAndServe()
		if err == nil {
			fmt.Println("error")
		}
	}()

	c := make(chan os.Signal)
	signal.Notify(c, syscall.SIGINT, syscall.SIGTERM)
	<-c
	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
	err := server.Shutdown(ctx)
	if err != nil {
		cancel()
	}
}

  

    方法二:同步子协程的状态给主协程让其等待子协程处理完成。

func main() {
	engine := gin.Default()
	engine.Handle("GET", "/hello", func(context *gin.Context) {
		context.JSON(http.StatusOK, gin.H{
			"err":  0,
			"data": []string{},
		})
		time.Sleep(5 * time.Second)
	})

	server := http.Server{
		Addr:    ":8081",
		Handler: engine,
	}

	var wg sync.WaitGroup
	wg.Add(1)
	go func() {
		c := make(chan os.Signal)
		signal.Notify(c, syscall.SIGINT, syscall.SIGTERM)
		<-c
		ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
		err := server.Shutdown(ctx)
		if err != nil {
			cancel()
		}
		wg.Done()
	}()

	err := server.ListenAndServe()
	if err == nil {
		fmt.Println("error")
	}
	wg.Wait()
}
posted @ 2021-07-06 15:05  Cgj20060102030405  阅读(292)  评论(0)    收藏  举报