返回顶部
首页 > 资讯 > 后端开发 > GO >Golang怎么优雅的终止一个服务
  • 247
分享到

Golang怎么优雅的终止一个服务

2023-06-29 14:06:44 247人浏览 安东尼
摘要

今天小编给大家分享一下golang怎么优雅的终止一个服务的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。前言采用常规方式启动一

今天小编给大家分享一下golang怎么优雅的终止一个服务的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。

前言

采用常规方式启动一个 Golang Http 服务时,若服务被意外终止或中断,即未等待服务对现有请求连接处理并正常返回且亦未对服务停止前作一些必要的处理工作,这样即会造成服务硬终止。这种方式不是很优雅。

参看如下代码,该 http 服务请求路径为根路径,请求该路径,其会在 2s 后返回 hello。

var addr = flag.String("server addr", ":8080", "server address")func main() {    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {        time.Sleep(2 * time.Second)        fmt.Fprintln(w, "hello")    })    http.ListenAndServe(*addr, nil)}

若服务启动后,请求http://localhost:8080/,然后使用 Ctrl+C 立即中断服务,服务即会立即退出(exit status 2),请求未正常返回(ERR_CONNECTioN_REFUSED),连接即马上断了。

接下来介绍使用 http.Server 的 Shutdown 方法结合 signal.Notify 来优雅的终止服务。

1 Shutdown 方法

Golang http.Server 结构体有一个终止服务的方法 Shutdown,其 go doc 如下。

func (srv *Server) Shutdown(ctx context.Context) error
    Shutdown gracefully shuts down the server without interrupting any active
    connections. Shutdown works by first closing all open listeners, then
    closing all idle connections, and then waiting indefinitely for connections
    to return to idle and then shut down. If the provided context expires before
    the shutdown is complete, Shutdown returns the context's error, otherwise it
    returns any error returned from closing the Server's underlying Listener(s).

    When Shutdown is called, Serve, ListenAndServe, and ListenAndServeTLS
    immediately return ErrServerClosed. Make sure the program doesn't exit and
    waits instead for Shutdown to return.

    Shutdown does not attempt to close nor wait for hijacked connections such as
    websockets. The caller of Shutdown should separately notify such long-lived
    connections of shutdown and wait for them to close, if desired. See
    ReGISterOnShutdown for a way to register shutdown notification functions.

    Once Shutdown has been called on a server, it may not be reused; future
    calls to methods such as Serve will return ErrServerClosed.

由文档可知:

使用 Shutdown 可以优雅的终止服务,其不会中断活跃连接。

其工作过程为:首先关闭所有开启的监听器,然后关闭所有闲置连接,最后等待活跃的连接均闲置了才终止服务。

若传入的 context 在服务完成终止前已超时,则 Shutdown 方法返回 context 的错误,否则返回任何由关闭服务监听器所引起的错误。

当 Shutdown 方法被调用时,Serve、ListenAndServe 及 ListenAndServeTLS 方法会立刻返回 ErrServerClosed 错误。请确保 Shutdown 未返回时,勿退出程序。

对诸如 WEBSocket 等的长连接,Shutdown 不会尝试关闭也不会等待这些连接。若需要,需调用者分开额外处理(诸如通知诸长连接或等待它们关闭,使用 RegisterOnShutdown 注册终止通知函数)。

一旦对 server 调用了 Shutdown,其即不可再使用了(会报 ErrServerClosed 错误)。

有了 Shutdown 方法,我们知道在服务终止前,调用该方法即可等待活跃连接正常返回,然后优雅的关闭。

但服务启动后的某一时刻,程序如何知道服务被中断了呢?服务被中断时如何通知程序,然后调用 Shutdown 作处理呢?接下来看一下系统信号通知函数的作用。

2 signal.Notify 函数

signal 包的 Notify 函数提供系统信号通知的能力,其 go doc 如下。

func Notify(c chan<- os.Signal, sig ...os.Signal)
    Notify causes package signal to relay incoming signals to c. If no signals
    are provided, all incoming signals will be relayed to c. Otherwise, just the
    provided signals will.

    Package signal will not block sending to c: the caller must ensure that c
    has sufficient buffer space to keep up with the expected signal rate. For a
    channel used for notification of just one signal value, a buffer of size 1
    is sufficient.

    It is allowed to call Notify multiple times with the same channel: each call
    expands the set of signals sent to that channel. The only way to remove
    signals from the set is to call Stop.

    It is allowed to call Notify multiple times with different channels and the
    same signals: each channel receives copies of incoming signals
    independently.

由文档可知:

参数 c 是调用者的信号接收通道,Notify 可将进入的信号转到 c。sig 参数为需要转发的信号类型,若不指定,所有进入的信号都将会转到 c。

信号不会阻塞式的发给 c:调用者需确保 c 有足够的缓冲空间,以应对指定信号的高频发送。对于用于通知仅一个信号值的通道,缓冲大小为 1 即可。

同一个通道可以调用 Notify 多次:每个调用扩展了发送至该通道的信号集合。仅可调用 Stop 来从信号集合移除信号。

允许不同的通道使用同样的信号参数调用 Notify 多次:每个通道独立的接收进入信号的副本。

综上,有了 signal.Notify,传入一个 chan 并指定中断参数,这样当系统中断时,即可接收到信号。

参看如下代码,当使用 Ctrl+C 时,c 会接收到中断信号,程序会在打印“program interrupted”语句后退出。

func main() {    c := make(chan os.Signal)    signal.Notify(c, os.Interrupt)    <-c    log.Fatal("program interrupted")}
$ go run main.go

Ctrl+C

2019/06/11 17:59:11 program interrupted
exit status 1

3 Server 优雅的终止

接下来我们使用如上 signal.Notify 结合 http.Server 的 Shutdown 方法实现服务优雅的终止。

如下代码,Handler 与文章开始时的处理逻辑一样,其会在2s后返回 hello。

创建一个 http.Server 实例,指定端口与 Handler。

声明一个 processed chan,其用来保证服务优雅的终止后再退出主 goroutine。

新启一个 goroutine,其会监听 os.Interrupt 信号,一旦服务被中断即调用服务的 Shutdown 方法,确保活跃连接的正常返回(本代码使用的 Context 超时时间为 3s,大于服务 Handler 的处理时间,所以不会超时)。

处理完成后,关闭 processed 通道,最后主 goroutine 退出。

代码同时托管在 GitHub,欢迎关注(github.com/olzhy/go-excercises)。

var addr = flag.String("server addr", ":8080", "server address")func main() {    // handler    handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {        time.Sleep(2 * time.Second)        fmt.Fprintln(w, "hello")    })    // server    srv := http.Server{        Addr:    *addr,        Handler: handler,    }    // make sure idle connections returned    processed := make(chan struct{})    go func() {        c := make(chan os.Signal, 1)        signal.Notify(c, os.Interrupt)        <-c        ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)        defer cancel()        if err := srv.Shutdown(ctx); nil != err {            log.Fatalf("server shutdown failed, err: %v\n", err)        }        log.Println("server gracefully shutdown")        close(processed)    }()    // serve    err := srv.ListenAndServe()    if http.ErrServerClosed != err {        log.Fatalf("server not gracefully shutdown, err :%v\n", err)    }    // waiting for goroutine above processed    <-processed}

以上就是“Golang怎么优雅的终止一个服务”这篇文章的所有内容,感谢各位的阅读!相信大家阅读完这篇文章都有很大的收获,小编每天都会为大家更新不同的知识,如果还想学习更多的知识,请关注编程网GO频道。

您可能感兴趣的文档:

--结束END--

本文标题: Golang怎么优雅的终止一个服务

本文链接: https://lsjlt.com/news/325305.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • Golang怎么优雅的终止一个服务
    今天小编给大家分享一下Golang怎么优雅的终止一个服务的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。前言采用常规方式启动一...
    99+
    2023-06-29
  • 详解Golang如何优雅的终止一个服务
    目录前言1 Shutdown 方法2 signal.Notify 函数3 Server 优雅的终止总结前言 采用常规方式启动一个 Golang http 服务时,若服务被意外终止或中...
    99+
    2024-04-02
  • C#怎么优雅地终止线程
    今天小编给大家分享一下C#怎么优雅地终止线程的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。需求说明现在有一个需求:有一个后台...
    99+
    2023-07-05
  • 怎么在Java中终止一个线程
    这篇“怎么在Java中终止一个线程”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“怎么在Java中终止一个线程”文章吧。Thr...
    99+
    2023-07-05
  • Golang怎么使用channel实现一个优雅退出功能
    这篇文章主要介绍了Golang怎么使用channel实现一个优雅退出功能的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇Golang怎么使用channel实现一个优雅退出功能文章都会有所收获,下面我们一起来看看吧...
    99+
    2023-07-05
  • golang中怎么优雅地关闭http服务
    这篇文章主要介绍“golang中怎么优雅地关闭http服务”,在日常操作中,相信很多人在golang中怎么优雅地关闭http服务问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”golang中怎么优雅地关闭htt...
    99+
    2023-07-06
  • 怎么在Golang中优雅地关闭HTTP服务器
    这篇“怎么在Golang中优雅地关闭HTTP服务器”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“怎么在Golang中优雅地关...
    99+
    2023-07-05
  • 怎么优雅地打印一个Java对象
    本文小编为大家详细介绍“怎么优雅地打印一个Java对象”,内容详细,步骤清晰,细节处理妥当,希望这篇“怎么优雅地打印一个Java对象”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。提问者定义了这样一个类:publi...
    99+
    2023-06-16
  • 怎么终止linux邮箱服务
    要终止Linux上的邮件服务,可以按照以下步骤操作:1. 确定你所使用的邮件服务是哪个。常见的邮件服务有Postfix、Sendma...
    99+
    2023-08-25
    linux
  • golang怎么优雅的关机或重启
    本文小编为大家详细介绍“golang怎么优雅的关机或重启”,内容详细,步骤清晰,细节处理妥当,希望这篇“golang怎么优雅的关机或重启”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。优雅地关机或重启我们编写的We...
    99+
    2023-06-30
  • 亚马逊服务器终止服务怎么办
    1. 了解亚马逊服务器终止服务的原因 在处理亚马逊服务器终止服务的问题之前,首先需要了解终止服务的原因。亚马逊可能会终止服务,因为你的账户存在欠费、违反了服务条款或者安全问题等。如果你不知道终止服务的原因,可以通过联系亚马逊客服来获取更多...
    99+
    2023-10-27
    亚马逊 服务器
  • 亚马逊服务器终止服务怎么办理的
    查看终止服务的原因:在您的账户设置中,可以查看是否有“亚马逊服务器终止服务”的选项,该选项将指示您的服务器是否已经终止服务。如果没有,请联系亚马逊客户支持团队,了解如何取消服务。 取消服务:一旦服务器已经终止服务,您可以选择取消服务。在您...
    99+
    2023-10-27
    亚马逊 服务器
  • 亚马逊服务器终止怎么办理的
    1. 了解亚马逊服务器终止的原因 在处理亚马逊服务器终止问题之前,首先需要了解终止的原因。亚马逊可能会终止服务器实例,因为账户欠费、安全问题、违反服务条款等原因。如果您的服务器实例被终止,您将无法访问其中的数据和应用程序。 2. 备份数据...
    99+
    2023-10-27
    亚马逊 服务器
  • 怎么优雅地实现判断一个值是否在一个集合中
    本篇内容介绍了“怎么优雅地实现判断一个值是否在一个集合中”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!版本...
    99+
    2024-04-02
  • 怎么在Flutter上优雅地序列化一个对象
    本文小编为大家详细介绍“怎么在Flutter上优雅地序列化一个对象”,内容详细,步骤清晰,细节处理妥当,希望这篇“怎么在Flutter上优雅地序列化一个对象”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。序列化一个...
    99+
    2023-06-04
  • 亚马逊服务器终止服务怎么解决
    2、更新软件:更新服务器软件可以解决部分故障,包括系统更新、驱动更新和应用程序更新等。 3、检查网络连接:检查服务器与互联网的连接是否正常,确保网络带宽足够,并且确保网络设置正确。 4、检查防火墙和入侵检测系统:检查服务器防火墙和入侵检测...
    99+
    2023-10-27
    亚马逊 服务器
  • 亚马逊服务器终止服务怎么办理的呢
    检查AWS账号:如果您使用AWS云服务进行工作,首先需要登录AWS账号,确保没有异常情况。如果出现异常,可以尝试联系AWS客服寻求帮助。 重启服务器:如果AWS账号正常,可以通过AWS控制台重新启动服务器。在控制台中找到“重启”或“重新启...
    99+
    2023-10-27
    亚马逊 服务器
  • Linux怎么搭建一个golang服务器
    这篇文章主要介绍了Linux怎么搭建一个golang服务器的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇Linux怎么搭建一个golang服务器文章都会有所收获,下面我们一起来看看吧。一、预备知识在开始之前,你...
    99+
    2023-07-05
  • 亚马逊服务器被终止了怎么办
    1. 了解终止原因 当亚马逊服务器被终止时,首先需要了解终止的原因。亚马逊可能会终止服务器的原因包括: 未能支付账单 违反了服务条款 安全问题 资源使用不当 了解终止原因可以帮助你更好地解决问题。 2. 备份数据 在解决服务器终止问题...
    99+
    2023-10-27
    亚马逊 服务器
  • quartz怎么终止正在执行的任务
    要终止正在执行的任务,您需要使用Quartz的Scheduler对象来进行操作。您可以通过调用Scheduler对象的shutdow...
    99+
    2023-10-20
    quartz
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作