无聊聊聊GO,实现重载配置文件功能

原创
2018/05/21 18:22
阅读数 530

重载配置,大部分主流的服务器软件都支持,例如 mysql nginx php-fpm 都支持 reload 操作。

如果我们自己写程序如何实现呢?

我将一个程序分为几个阶段:

  1. 初始化:加载配置文件,注册各种服务

  2. 运行:启动各种服务

  3. 退出:cancel所有goroutine,wg.Wait(),其他收尾工作

重载配置触发过程在第3步,我通过 kill -USR1 发送一个信号给进程,进程捕获到以后做如下事情:

4 、cancel所有goroutine ,wait, 释放资源(mysql、redis等连接) 5、goto 第1步,重新加载配置文件,重新初始化服务,然后运行

为了统一管理mysql这类服务,我使用了一个包:

github.com/keepeye/go-container

大致代码如下:

package main

import (
	"context"
	"os"
	"syscall"
	"os/signal"
	"sync"
	"github.com/keepeye/go-container/container"
	"github.com/spf13/viper"
	"github.com/jinzhu/gorm"
	"time"
)

func registerServices() {
	// 注册配置服务
	container.Singleton("config", func(c *container.Container) interface{} {
		viper.AddConfigPath("./build")
		viper.SetConfigName("app")
		err := viper.ReadInConfig()
		if err != nil {
			panic(err)
		}
		return viper.GetViper()
	})

	// 注册数据库服务
	container.Singleton("db", func(c *container.Container) interface{} {
		config := c.Get("config").(*viper.Viper)
		//初始化数据库
		db, err := gorm.Open("mysql", config.GetString("database.dsn"))
		if err != nil {
			panic(err)
		}
		db.DB().SetMaxOpenConns(10)
		db.DB().SetMaxIdleConns(2)
		// 是否打印sql
		printSql := config.GetBool("database.print_sql")
		if printSql {
			db = db.LogMode(true)
		}
		// release的时候关闭db
		c.BeforeRelease(func() {
			db.Close()
		})
		return db
	})
}

func main() {
	
	//wg用来统一记录gorountine,以便程序结束时等待所有线程都退出
	wg := &sync.WaitGroup{}
	//使用context包,便于向所有goroutine发送退出信号
	ctx,cancel := context.WithCancel(context.Background())
	
	//注册所有服务
	START: registerServices()
	
	//模拟一个服务
        wg.Add(1)
	go func(ctx context.Context) {
                defer wg.Done()
		db := container.Get("mysql").(*gorm.DB)
		tick := time.Tick(1 * time.Second)
		for {
			select {
			case <-ctx.Done():
				return 
			case <-tick:
				user := struct {
					ID int `json:"id"`
				}{}
				db.Where("status = 1").Last(&user)
				//.....
			}
		}
	}(ctx)
	
	ch := make(chan os.Signal, 1)
	signal.Notify(ch, syscall.SIGINT, syscall.SIGKILL, syscall.SIGTERM, syscall.SIGUSR1)

	sig := <-ch

	switch sig {
	case syscall.SIGINT:
		fallthrough
	case syscall.SIGKILL:
		fallthrough
	case syscall.SIGTERM:
		cancel()
		wg.Wait()
		container.Release()
	// 重载配置	
	case syscall.SIGUSR1:
		cancel()
		wg.Wait()
		//release释放所有旧的连接
		container.Release()
		//清空服务实例,下次重新初始化的时候会使用新的配置参数
		container.Refresh()
		goto START
	}

}

展开阅读全文
Go
打赏
0
5 收藏
分享
加载中
更多评论
打赏
0 评论
5 收藏
0
分享
返回顶部
顶部