golang优雅管理应用关闭信号的插件库Death的使用

Golang优雅管理应用关闭信号的插件库Death的使用

Death是一个简单易用的库,可以帮助你更好地管理应用程序的关闭信号。

获取库

使用以下命令获取最新版本的Death库:

go get github.com/vrecan/death/v3

使用库

基本用法

package main

import (
	DEATH "github.com/vrecan/death/v3"
	SYS "syscall"
)

func main() {
	death := DEATH.NewDeath(SYS.SIGINT, SYS.SIGTERM) // 传入你想结束应用程序的信号
	// 当你想要阻塞等待关闭信号时
	death.WaitForDeath() // 当指定类型的信号发送到你的应用程序时,这个函数会结束
}

在关闭时关闭其他对象

Death的一个简单特性是它可以在关闭开始时关闭其他对象。

package main

import (
	"log"
	DEATH "github.com/vrecan/death/v3"
	SYS "syscall"
	"io"
)

func main() {
	death := DEATH.NewDeath(SYS.SIGINT, SYS.SIGTERM) // 传入你想结束应用程序的信号
	objects := make([]io.Closer, 0)

	objects = append(objects, &NewType{}) // 只要类型实现了Close方法,这就能工作

	// 当你想要阻塞等待关闭信号时
	err := death.WaitForDeath(objects...) // 当指定类型的信号发送到你的应用程序时,这个函数会结束
	if err != nil {
		log.Println(err)
		os.Exit(1)
	}
}

type NewType struct {
}

func (c *NewType) Close() error {
	return nil
}

使用匿名函数关闭

package main

import (
	DEATH "github.com/vrecan/death/v3"
	SYS "syscall"
)

func main() {
	death := DEATH.NewDeath(SYS.SIGINT, SYS.SIGTERM) // 传入你想结束应用程序的信号
	// 当你想要阻塞等待关闭信号时
	death.WaitForDeathWithFunc(func(){
		// 在关闭时做任何你想做的事情
	})
}

发布流程

发布分支规则:

  • 如果你要发布一个新的主版本,你需要从master分支创建一个名为release-branch.v#的分支(例如release-branch.v2表示2.x版本)
  • 如果你要发布现有主版本的次要或补丁更新,请确保将master合并到发布分支中

标记和发布版本的规则

当你准备好发布版本时,请确保你…

  1. 将你的更改合并到正确的发布分支
  2. 在本地检出发布分支(例如:git pull origin release-branch.v3
  3. 为你将要发布的特定版本创建一个新标签(例如:git tag v3.0.1
  4. 将标签推送到github(例如:git push origin v3.0.1
  5. 转到github中的发布标签页
  6. 选择目标分支作为发布分支并输入标签名称(标签名称应包括v,例如:v3.0.1
  7. 写一个标题和详细描述说明这个变更的具体内容
  8. 点击发布版本

更多关于golang优雅管理应用关闭信号的插件库Death的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于golang优雅管理应用关闭信号的插件库Death的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


Golang优雅管理应用关闭信号的插件库Death使用指南

Death是一个轻量级的Go库,用于优雅地管理应用程序的关闭信号。它可以帮助你在程序收到终止信号时,优雅地关闭所有goroutine和资源。

安装Death库

go get github.com/vrecan/death/v3

基本使用示例

package main

import (
	"context"
	"fmt"
	"time"
	
	"github.com/vrecan/death/v3"
)

func main() {
	// 创建Death实例
	d := death.NewDeath()
	
	// 模拟一个需要优雅关闭的服务
	go func() {
		for {
			select {
			case <-d.Dying():
				fmt.Println("服务正在关闭...")
				return
			default:
				fmt.Println("服务运行中...")
				time.Sleep(1 * time.Second)
			}
		}
	}()
	
	// 等待系统信号并优雅关闭
	d.WaitForDeath()
	fmt.Println("应用程序已优雅关闭")
}

高级功能

1. 自定义关闭信号

func main() {
	d := death.NewDeath(
		death.Signals(syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT),
	)
	
	go func() {
		<-d.Dying()
		fmt.Println("收到关闭信号,开始清理...")
		// 执行清理操作
	}()
	
	d.WaitForDeath()
}

2. 注册关闭回调函数

func main() {
	d := death.NewDeath()
	
	// 注册关闭时的回调函数
	d.RegisterBeforeDeath(func() {
		fmt.Println("执行关闭前的清理工作")
		time.Sleep(2 * time.Second) // 模拟清理耗时
	})
	
	go func() {
		for {
			select {
			case <-d.Dying():
				fmt.Println("服务正在关闭...")
				return
			default:
				fmt.Println("服务运行中...")
				time.Sleep(1 * time.Second)
			}
		}
	}()
	
	d.WaitForDeath()
}

3. 结合context使用

func main() {
	d := death.NewDeath()
	ctx := context.Background()
	
	// 创建一个可以感知Death的context
	ctx, cancel := context.WithCancel(ctx)
	defer cancel()
	
	go func() {
		<-d.Dying()
		fmt.Println("收到关闭信号,取消context")
		cancel()
	}()
	
	go func() {
		for {
			select {
			case <-ctx.Done():
				fmt.Println("context被取消,停止服务")
				return
			default:
				fmt.Println("服务运行中...")
				time.Sleep(1 * time.Second)
			}
		}
	}()
	
	d.WaitForDeath()
}

实际应用示例

package main

import (
	"fmt"
	"net/http"
	"sync"
	"time"
	
	"github.com/vrecan/death/v3"
)

type Server struct {
	httpServer *http.Server
	wg         sync.WaitGroup
}

func NewServer() *Server {
	mux := http.NewServeMux()
	mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("Hello, World!"))
	})
	
	return &Server{
		httpServer: &http.Server{
			Addr:    ":8080",
			Handler: mux,
		},
	}
}

func (s *Server) Start() {
	s.wg.Add(1)
	go func() {
		defer s.wg.Done()
		fmt.Println("HTTP服务器启动")
		if err := s.httpServer.ListenAndServe(); err != http.ErrServerClosed {
			fmt.Printf("HTTP服务器错误: %v\n", err)
		}
	}()
}

func (s *Server) Stop() error {
	fmt.Println("停止HTTP服务器...")
	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()
	return s.httpServer.Shutdown(ctx)
}

func main() {
	server := NewServer()
	server.Start()
	
	d := death.NewDeath()
	
	// 注册关闭时的回调
	d.RegisterBeforeDeath(func() {
		fmt.Println("开始优雅关闭...")
		if err := server.Stop(); err != nil {
			fmt.Printf("关闭服务器时出错: %v\n", err)
		}
		server.wg.Wait() // 等待所有goroutine完成
	})
	
	fmt.Println("应用程序运行中,按Ctrl+C停止...")
	d.WaitForDeath()
	fmt.Println("应用程序已完全关闭")
}

最佳实践

  1. 资源清理:确保所有打开的文件、数据库连接、网络连接等在关闭时都被正确释放

  2. 超时控制:为关闭操作设置合理的超时时间,避免无限等待

  3. 并发安全:确保关闭操作是并发安全的

  4. 日志记录:记录关闭过程中的关键步骤,便于问题排查

  5. 分级关闭:按照依赖关系有序关闭服务,例如先关闭接收新请求,再处理已有请求,最后关闭资源

Death库提供了一种简单而强大的方式来管理Go应用程序的生命周期,特别是在需要优雅关闭的场景下非常有用。

回到顶部