文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

go关闭Graceful Shutdown服务的几种方法

2023-07-06 14:14

关注

本篇文章和大家了解一下go关闭Graceful Shutdown服务的几种方法。有一定的参考价值,有需要的朋友可以参考一下,希望对大家有所帮助。

目录

Shutdown方法

Go1.8之后有了Shutdown方法,用来优雅的关闭(Graceful Shutdown)服务。

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

这个方法会在调用时进行下述操作:

关闭所有open listeners

关闭所有idle connections

无限期等待connections回归idle状态

之后关闭服务

注:3的无限期等待可以用context的超时来解决。

RegisterOnShutdown方法

Go1.9之后有了RegisterOnShutdown方法,用来在优雅的关闭服务的同时处理一些退出任务。

func (srv *Server) RegisterOnShutdown(f func())

关于RegisterOnShutdown如何生效,我们看代码。

type Server struct {    ...    onShutdown []func()}func (srv *Server) RegisterOnShutdown(f func()) {    srv.mu.Lock()    srv.onShutdown = append(srv.onShutdown, f)    srv.mu.Unlock()}func (srv *Server) Shutdown(ctx context.Context) error {    ...    srv.mu.Lock()    ...    for _, f := range srv.onShutdown {        go f()    }    srv.mu.Unlock()    ...}

由代码可知,在通过RegisterOnShutdown进行注册之后,这些函数被放入一个函数切片中,并在Shutdown被调用的时候,为每个函数启动了一个goroutine进行处理。

但由于没有进行后续处理,于是这里有个小问题,Shutdown是不等待这些处理函数结束的,就可能比这些处理函数先完成并进而结束程序。

package mainimport (    "context"    "log"    "net/http"    "os"    "os/signal"    "time")func main() {    var srv http.Server    srv.RegisterOnShutdown(func() {        time.Sleep(3 * time.Second)        log.Println("Exit func")    })    idleConnsClosed := make(chan struct{})    go func() {        sigint := make(chan os.Signal, 1)        signal.Notify(sigint, os.Interrupt)        <-sigint        // We received an interrupt signal, shut down.        if err := srv.Shutdown(context.Background()); err != nil {            // Error from closing listeners, or context timeout:            log.Printf("HTTP server Shutdown: %v", err)        }        close(idleConnsClosed)    }()    if err := srv.ListenAndServe(); err != http.ErrServerClosed {        // Error starting or closing listener:        log.Fatalf("HTTP server ListenAndServe: %v", err)    }    <-idleConnsClosed}

运行时Ctrl+c之后,服务立刻结束了,并未等待log.Println("Exit func")的输出。

sync.WaitGroup处理退出函数

为了解决这个问题我们使用sync.WaitGroup来处理这些退出函数,于是我们有了下面的代码(解耦并增加了一些日志):

package mainimport (    "context"    "log"    "net/http"    "os"    "os/signal"    "sync"    "time")func main() {    var srv http.Server    var wg sync.WaitGroup    register := func(f func()) {        wg.Add(1)        log.Println("Exit func register")        srv.RegisterOnShutdown(func() {            defer wg.Done()            f()            log.Println("Exit func done")        })    }    register(func() {        time.Sleep(3 * time.Second)        log.Println("Called on Shutdown")    })    idleConnsClosed := make(chan struct{})    go func() {        sigint := make(chan os.Signal, 1)        signal.Notify(sigint, os.Interrupt)        <-sigint        // We received an interrupt signal, shut down.        log.Println("Shutdown start")        if err := srv.Shutdown(context.Background()); err != nil {            // Error from closing listeners, or context timeout:            log.Printf("HTTP server Shutdown: %v", err)        }        close(idleConnsClosed)    }()    if err := srv.ListenAndServe(); err != http.ErrServerClosed {        // Error starting or closing listener:        log.Fatalf("HTTP server ListenAndServe: %v", err)    }    <-idleConnsClosed    log.Println("Shutdown finish")    wg.Wait()}

我们在RegisterOnShutdown时使用了time.Sleep(3 * time.Second)来模拟一个长时间的退出程序,并且在"Shutdown finish"之后进行等待,等待退出程序完成任务。

执行日志如下:

2023/05/12 16:48:53 Exit func register
^C2023/05/12 16:48:54 Shutdown start
2023/05/12 16:48:54 Shutdown finish
2023/05/12 16:48:57 Called on Shutdown
2023/05/12 16:48:57 Exit func done

可以看到这个服务本身很轻,Shutdown start之后立刻就finish并来到wg.Wait(),并等待register的函数完成之后再退出程序。

另外,如果在服务运行的过程中需要启动一些其他的任务,也可以使用

wg.Add(1)go func() {    defer wg.Done()    ...}

来保证任务在服务Shutdown之后可以顺利完成。

以上就是go关闭Graceful Shutdown服务的几种方法的简略介绍,当然详细使用上面的不同还得要大家自己使用过才领会。如果想了解更多,欢迎关注编程网行业资讯频道哦!

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯