Go语言实现优雅关机和重启的示例详解

 更新时间:2025年04月21日 09:35:30   作者:大学生亨亨  
优雅的关机是指在关闭服务之前,先让服务处理完当前正在处理的请求,然后再关闭服务,本文主要为大家详细介绍了如何使用Go语言实现优雅关机和重启,感兴趣的小伙伴可以参考一下

一、优雅关机

生活化例子

餐馆关门:你去餐馆吃火锅,刚坐下点完菜(客户端发请求),餐馆老板突然接到通知要停电(收到关机指令)。老板很贴心,先停止接待新客人(停止接收新请求),等你这桌和其他正在吃饭的客人(正在处理的请求)都吃完了,再关门走人。这样你的火锅就能安安全全吃完,不会有任何损失。

代码示例

package main
 
import (
	"context"
	"log"
	"net/http"
	"os"
	"os/signal"
	"syscall"
	"time"
 
	"github.com/gin-gonic/gin"
)
 
func main() {
	// 创建路由器
	router := gin.Default()
	router.GET("/cook-hotpot", func(c *gin.Context) {
		time.Sleep(5 * time.Second) // 模拟煮火锅需要时间
		c.String(http.StatusOK, "火锅煮好了,可以吃啦!")
	})
 
	// 创建服务器
	srv := &http.Server{
		Addr:    ":8080",
		Handler: router,
	}
 
	// 在单独的goroutine中启动服务器
	go func() {
		if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
			log.Fatalf("服务器监听错误: %s", err)
		}
	}()
 
	// 创建一个通道来接收系统信号
	quit := make(chan os.Signal, 1)
	signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM) // 监听Ctrl+C和系统终止信号
 
	// 阻塞等待信号
	<-quit
	log.Println("开始优雅关机...")
 
	// 设置一个5秒超时的上下文
	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()
 
	// 调用Shutdown方法优雅关闭服务器
	if err := srv.Shutdown(ctx); err != nil {
		log.Fatalf("服务器优雅关机失败: %s", err)
	}
 
	log.Println("服务器已安全退出")
}

验证效果

  • 运行上面的代码,启动服务。
  • 打开浏览器访问 http://127.0.0.1:8080/cook-hotpot,模拟开始煮火锅。
  • 在终端迅速执行 Ctrl+C 命令,向程序发送关机信号。
  • 观察程序不会立即退出,而是等待火锅煮好(请求处理完)后才退出,实现优雅关机。

二、优雅重启

生活化例子

保安换班:小区门口有两名保安,保安A(老进程)正在值班,保安B(新进程)来接班。保安A不会直接走人,而是等手头的事(比如处理一辆正在进入的车)忙完,再让保安B接管工作。这样小区门口的秩序不会因为换班而受到影响。

代码示例

package main
 
import (
	"log"
	"net/http"
	"time"
 
	"github.com/fvbock/endless"
	"github.com/gin-gonic/gin"
)
 
func main() {
	// 创建路由器
	router := gin.Default()
	router.GET("/greet", func(c *gin.Context) {
		time.Sleep(5 * time.Second) // 模拟处理请求需要时间
		c.String(http.StatusOK, "你好呀,欢迎来到小区!")
	})
 
	// 使用endless启动服务器,支持优雅重启
	if err := endless.ListenAndServe(":8080", router); err != nil {
		log.Fatalf("服务器监听错误: %s", err)
	}
 
	log.Println("服务器已安全退出")
}

验证效果

  • 编译并运行上述代码,终端会输出当前进程的 PID。
  • 修改代码中处理请求函数的返回值,如将 "你好呀,欢迎来到小区!" 修改为 "欢迎光临,小区新保安在此!",然后重新编译。
  • 打开浏览器访问 http://127.0.0.1:8080/greet,模拟车辆进入小区。
  • 在终端迅速执行 kill -1 <PID> 命令,向程序发送优雅重启信号。
  • 等当前请求处理完(保安A处理完手头的事),再次访问时会收到新的欢迎语,说明在不影响当前请求的情况下完成了优雅重启,同时进程号也变成了新的(保安B接班)。

三、总结

优雅关机和优雅重启的核心就是“有始有终”,不甩手不管正在做的事。

优雅关机就像餐馆老板等你吃完火锅再关门,通过监听系统信号(如Ctrl+C),调用Shutdown()方法,停止接收新请求并等待现有请求处理完。

优雅重启就像保安换班,使用endless库监听特定信号(如SIGHUP),启动新进程处理新请求,同时让老进程处理完现有请求再退出。

在实际项目中,根据需求选择:需要安全关闭服务就用优雅关机;需要更新代码且不影响现网运行就用优雅重启。

到此这篇关于Go语言实现优雅关机和重启的示例详解的文章就介绍到这了,更多相关Go语言优雅关机和重启内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 使用Go基于WebSocket构建千万级视频直播弹幕系统的代码详解

    使用Go基于WebSocket构建千万级视频直播弹幕系统的代码详解

    这篇文章主要介绍了使用Go基于WebSocket构建千万级视频直播弹幕系统,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-07-07
  • Go container包的介绍

    Go container包的介绍

    这篇文章主要介绍了Go container包,go语言container包中有List和Element容器ist和Element都是结构体类型。结构体类型有一个特点,那就是它们的零值都会是拥有其特定结构,但没有任何定制化内容的值,相当于一个空壳,下面一起进文章来了解具体内容吧
    2021-12-12
  • Golang合并yaml文件过程逐步讲解

    Golang合并yaml文件过程逐步讲解

    之前一直从事java开发,习惯了使用yaml文件的格式,尤其是清晰的层次结构、注释,下面这篇文章主要给大家介绍了关于Golang合并yaml文件的相关资料,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
    2023-01-01
  • 三种Golang数组拷贝的实现方式与性能分析

    三种Golang数组拷贝的实现方式与性能分析

    在 Golang 中,有多种方式可以进行数组的拷贝,本文将对其中的三种方式进行性能分析,并比较它们的优缺点,感兴趣的小伙伴可以跟随小编一起学习一下
    2023-06-06
  • Go语言继承功能使用结构体实现代码重用

    Go语言继承功能使用结构体实现代码重用

    今天我来给大家介绍一下在 Go 语言中如何实现类似于继承的功能,让我们的代码更加简洁和可重用,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2024-01-01
  • go语言使用Chromedp实现二维码登陆教程示例源码

    go语言使用Chromedp实现二维码登陆教程示例源码

    这篇文章主要为大家介绍了go语言使用Chromedp实现二维码登陆示例源码,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-04-04
  • go select编译期的优化处理逻辑使用场景分析

    go select编译期的优化处理逻辑使用场景分析

    select 是 Go 中的一个控制结构,类似于用于通信的 switch 语句。每个 case 必须是一个通信操作,要么是发送要么是接收。接下来通过本文给大家介绍go select编译期的优化处理逻辑使用场景分析,感兴趣的朋友一起看看吧
    2021-06-06
  • Go语言开发编程规范命令风格代码格式

    Go语言开发编程规范命令风格代码格式

    这篇文章主要为大家介绍了Go语言开发编程规范命令风格代码格式,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-06-06
  • go语言调用其他包中的函数简单示例

    go语言调用其他包中的函数简单示例

    这篇文章主要给大家介绍了关于go语言调用其他包中的函数的相关资料,文中还介绍了Go语言同一个包中不同文件之间函数调用的相关问题,需要的朋友可以参考下
    2023-01-01
  • golang使用os/exec库查询进程方式

    golang使用os/exec库查询进程方式

    本文介绍了使用Go语言os/exec查询进程的方法,并提供了两种方式,第一种方式输出了当前系统所有运行的进程,第二种方式可以过滤出指定进程的信息
    2026-04-04

最新评论