golang 优雅关闭服务

文章介绍了如何在Gin框架中实现优雅关闭HTTP服务,确保所有任务执行完毕后再关闭,防止数据异常。通过`Shutdown`函数配合上下文管理,监听系统信号来实现优雅关闭,并提供了一个示例代码展示具体操作流程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、什么是优雅关闭服务

先把在执行的任务执行完成,再关闭服务,防止中断服务造成程序错误,数据异常等影响。

在这里插入图片描述

二、使用函数

语法:


func (srv *Server) Shutdown(ctx context.Context) error

作用: Shutdown优雅地关闭服务器,而不会中断任何活动连接。

工作原理: 首先关闭所有打开的侦听器,然后关闭所有空闲连接,然后无限期地等待连接恢复空闲状态,然后关闭。 如果提供的上下文在关闭完成之前过期,shutdown将返回上下文的错误,否则将返回关闭服务器底层侦听器返回的任何错误。

三、使用案例

例:


package main

import (
	"context"
	"log"
	"net/http"
	"os"
	"os/signal"
	"time"
	"syscall"

	"github.com/gin-gonic/gin"
)

func main() {
	router := gin.Default()
	router.GET("/", func(c *gin.Context) {
		time.Sleep(5 * time.Second)
		c.String(http.StatusOK, "Welcome Gin Server")
	})

	srv := &http.Server{
		Addr:    ":8080",
		Handler: router,
	}

	go func() {
		// 服务连接
		if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
			log.Fatalf("listen: %s\n", err)
		}
	}()

	// 创建一个无缓冲通道
	quit := make(chan os.Signal)
	signal.Notify(quit, syscall.SIGINT, syscall.SIGHUP, syscall.SIGTERM)
	
	// 在未接受到信号时,通道发生阻塞。
	<-quit
	
	log.Println("Shutdown Server ...")

	// 等待中断信号以优雅地关闭服务器(设置 5 秒的超时时间)
	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()
	
	// 执行关闭服务操作
	if err := srv.Shutdown(ctx); err != nil {
		log.Fatal("Server Shutdown:", err)
	}
	
	log.Println("Server exiting")
}

Go语言(golang)并没有内置的优雅关机机制,因为它强调简洁性和直接操作系统资源的能力。但是,如果你想在程序中实现类似的功能,通常会在退出前完成一些清理工作,比如关闭数据库连接、停止定时任务等,以避免数据丢失或资源泄漏。 在 Go 中,你可以使用 `os.Exit()` 来终止程序,但这不是一个优雅的方式,因为这会立即终止程序执行,不会给已启动的 goroutines 提供清理时间。为了实现“优雅”的退出,可以采用以下步骤: 1. 使用 channels 或 sync.WaitGroup 等工具管理 goroutines 的执行,当需要结束时,发送信号通知它们关闭。 2. 在 main 函数中处理退出逻辑,并确保所有的协程都执行完毕。 3. 可以考虑使用第三方库如 `github.com/tools/gc` 进行垃圾回收,但它并不能保证所有依赖都被正确关闭。 下面是一个简单的示例,展示如何通过 channels 来实现优雅的退出: ```go package main import ( "fmt" "os" "time" ) func worker(stopCh <-chan struct{}) { // 这里模拟耗时的操作 for { select { case <-stopCh: fmt.Println("Worker stopped") return default: time.Sleep(5 * time.Second) } } } func main() { stopCh := make(chan struct{}) defer close(stopCh) // 设置默认通道关闭,确保所有worker都会收到停止信号 for i := 0; i < 3; i++ { go worker(stopCh) } // 给所有worker发出停止信号,等待他们完成 time.Sleep(time.Second * 10) fmt.Println("Shutting down...") os.Exit(0) } ``` 在这个例子中,`main` 主函数会等待所有 worker 完成后再退出。如果想让这个过程更可控,还可以添加错误处理和超时逻辑。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值