Hertz 学习笔记(13)

282 阅读2分钟

今天学习服务器的优雅退出。之前简单看过其他人的分享说 run()spin() 相关的话题好像和这个就有关系。

hertz server 如何优雅退出的示例

/*
 * Copyright 2022 CloudWeGo Authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package main

import (
	"context"
	"fmt"
	"time"

	"github.com/cloudwego/hertz/pkg/app/server"
)

func main() {
	// Maximum wait time before exit, if not specified the default is 5s
	h := server.Default(server.WithHostPorts("127.0.0.1:8080"), server.WithExitWaitTime(3*time.Second))

	h.OnShutdown = append(h.OnShutdown, func(ctx context.Context) {
		fmt.Println("hook 1")
		<-ctx.Done()
		fmt.Println("exit timeout!")
	})

	h.OnShutdown = append(h.OnShutdown, func(ctx context.Context) {
		fmt.Println("hook 2")
	})

	h.Spin()
}

从这个例子的代码里看只看到设置等待时间和在 OnShutdown 上面写回调函数。说实话我觉得应该还有更多的信息在文档里:

Hertz 优雅退出的过程分 6 步:

  1. 设置 engine 状态为 closed
  2. 顺序非阻塞触发回调函数 []OnShutDown(与标准包 net/http 一致),Select 等待回调函数执行完成或者超时返回
  3. Select 等待业务协程退出:
    • 对于 netpoll 网络库,开启默认1s(netpoll 中设置,暂时不可更改)的 ticker,定时查看 active conn(业务 handle 退出且连接不处于阻塞读状态)是否为0;对于 go net 网络库,则关闭监听,不对连接做处理。
    • 等待超时时间为 ExitWaitTime 的 context 触发,默认 5s
  4. 注册中心注销对应服务
  5. 关闭网络库的信号监听
  6. 对处于关闭过程中的请求回包统一带上 Connection:Close header

我们这个例子里可以看到回调函数设置了两个,第一个里面的 <-ctx.Done() 应该是在关各种业务, 在 server 创建的时候就已经设置了 ExitWaitTime,然后看是这个超时时间先到还是业务先退出完或者是用户要手动退出,后面就和 456 步骤一样了。

文档里还介绍了如何自定义信号处理方式,这个就是前面谈到的到底是超时触发的还是终端连接断开还是用户的 Ctrl + c 触发的,信号的处理逻辑也是可以自己定义的。

Hertz 使用 waitSignal 函数作为信号处理的默认实现方式,处理如下:

  • 当接收到 SIGTERM 系统信号时触发立即退出。
  • 当接收到 SIGHUP|SIGINT 系统信号时触发优雅退出。

当信号处理的默认实现方式无法满足需求时,可通过 SetCustomSignalWaiter 来自定义信号处理方式。

package main

import (
	"github.com/cloudwego/hertz/pkg/app/server"
)

func main() {
	h := server.New()
	h.SetCustomSignalWaiter(func(err chan error) error {
		return nil
	})
	...
}

当自定义信号处理函数返回 error 时 Hertz 会立即退出,其他情况下则会优雅退出。

感觉这里有点乱,要不下一期暂停例子学习,再深挖一下这一块的内容?