Go语言实现配置热加载的方法分享

作者:tracy小猫 时间:2024-02-07 04:02:47 

概述

web项目,经常需要热启动各种各样的配置信息,一旦这些服务发生变更,我们需要重新启动web server,以使配置生效,实现配置热加载。这里有几种方法实现这个需求。

go 定时器协程实现

项目结构

首先来看一下整个项目的目录结构:

- dyconfig // 项目地址
  - config   // 配置文件目录
      - api.yaml  // 采用yaml格式文件
  - global // 代码文件夹
      - config
              - config_define
              - init
              - reload
  - go.mod // go package管理依赖的包文件
  - go.sum // go package管理打包产生的文件
  - main.go // web server的入口,主函数

代码细节

接下来依次看一下各文件的主体内容:

conf/api.yaml文件定义了配置项,包含server的host及port信息。

service:
   server:
         env: dev
         host: 127.0.0.1
         port: 9902

global/init.go

package global
import (
"context"
"path"
)
type Config struct {
Conf struct {
   FilePath       string
   LastModifyTime int64
}
ctx    context.Context
cancel context.CancelFunc
}
func NewConfig() (*Config, error) {
conf := new(Config)
conf.ctx, conf.cancel = context.WithCancel(context.Background())
conf.Conf.FilePath = path.Join("./config", "api.yaml")
APIconfig = conf.loadRoute()
go conf.reload() //开启协程监听routeNotify
go func() {
   for {
      select {
      case lastModifyTime, ok := <-routeNotify:
         if !ok {
            return
         }
         conf.Conf.LastModifyTime = lastModifyTime
         route := routeAtomic.Load().(*APIConf)
         if route != nil {
            APIconfig = route
         }
      }
   }
}()
return conf, nil
}
func (c *Config) Stop() {
c.cancel()
}

定义Config 根据LastModifyTime 判断是否有发生变化,FilePath为文件路径

go conf.reload()

开启协程监听routeNotify,routeNotify内容是文件修改时间的timestamp

global/reload.go

package global
import (
  "fmt"
  "gopkg.in/yaml.v3"
  "io/ioutil"
  "os"
  "sync/atomic"
  "time"
)
const (
  CheckInterval = 5 * time.Second
)
var (
  routeAtomic atomic.Value //原子性,解决并发问题
  routeNotify = make(chan int64) //channel 放入timestamp
)
func (c *Config) reload() {
  ticker := time.NewTicker(CheckInterval)
  defer ticker.Stop()
  for {
     select {
     case <-c.ctx.Done():
        close(routeNotify)
        return
     case <-ticker.C:
        if f, err := os.Stat(c.Route.FilePath); err != nil {
           fmt.Println(err)
        } else if f.ModTime().Unix() != c.Route.LastModifyTime {
           if c.Route.LastModifyTime == 0 {
              c.Route.LastModifyTime = f.ModTime().Unix()
           } else {
              routeAtomic.Store(c.loadConfig())
              routeNotify <- f.ModTime().Unix()
              fmt.Println("配置文件发生变化")
           }
        }
     }
  }
}
func (c *Config) loadConfig() *APIConf {
  if fp, err := ioutil.ReadFile(c.Route.FilePath); err != nil {
     fmt.Println(err)
     return nil
  } else {
     route := new(APIConf)
     if err := yaml.Unmarshal(fp, &route); err != nil {
        return nil
     }
     return route
  }
}

定时器监听文件的修改时间与LastModifyTime是否相同,如果不同,则

package global
var (
  APIconfig = new(APIConf)
)
package global
type ServiceConf struct {
  Server struct {
     Env  string `yaml:"env"`
     Host string `yaml:"host"`
     Port string  `yaml:"port"`
  } `yaml:"server"`
}
type APIConf struct {
  Service ServiceConf `yaml:"service"`
}

mian

package main
import (
  "dyconfig/global"
  "fmt"
  "github.com/gin-gonic/gin"
)
func main() {
  if conf, err := global.NewConfig(); err != nil { // 初始化配置
     fmt.Println(err)
  } else {
     defer conf.Stop()
  }
  gin.SetMode(gin.DebugMode)
  r := gin.Default()
  r.GET("/ping", func(context *gin.Context) {
     fmt.Println("当前host是: ", global.APIconfig.Service.Server.Host)
     fmt.Println("当前port是: ", global.APIconfig.Service.Server.Port)
     context.JSON(
        200, gin.H{
           "host": global.APIconfig.Service.Server.Host,
           "port": &global.APIconfig.Service.Server.Port,
        })
  })
  port := global.APIconfig.Service.Server.Port
  fmt.Println("当前host是: ", global.APIconfig.Service.Server.Host)
  fmt.Println("当前port是: ", global.APIconfig.Service.Server.Port)
  port = ":" + port
  _ = r.Run(port)
}

调用示例

1.第一次调用,port为9902

Go语言实现配置热加载的方法分享

Go语言实现配置热加载的方法分享

2. 修改config ,port为9903

Go语言实现配置热加载的方法分享

Go语言实现配置热加载的方法分享

Go语言实现配置热加载的方法分享

来源:https://juejin.cn/post/7185563516094316600

标签:Go,配置,热加载
0
投稿

猜你喜欢

  • python GUI库图形界面开发之PyQt5控件QTableWidget详细使用方法与属性

    2022-08-13 22:06:58
  • python3爬虫中多线程进行解锁操作实例

    2021-04-29 00:16:42
  • JS与Ajax Get和Post在使用上的区别实例详解

    2024-04-23 09:07:40
  • vscode配置远程开发与免密登录的技巧

    2023-04-29 02:43:41
  • [翻译]网页设计中的模式窗口

    2009-05-29 18:00:00
  • python实现textrank关键词提取

    2021-11-01 16:47:58
  • SQL Server异常代码处理的深入讲解

    2024-01-22 11:42:58
  • IDEA中使用Git拉取代码时报 Git pull failed原因及解决方法

    2022-10-01 21:28:36
  • 浅谈python中的@以及@在tensorflow中的作用说明

    2021-06-10 01:50:22
  • pandas object格式转float64格式的方法

    2022-05-26 15:58:53
  • opencv python图像梯度实例详解

    2021-05-17 23:26:30
  • 浅谈PYTHON 关于文件的操作

    2022-06-07 19:54:58
  • Python利用Pillow(PIL)库实现验证码图片的全过程

    2022-05-18 21:27:47
  • python实现TCP服务器端与客户端的方法详解

    2023-05-17 09:39:39
  • 在Golang中执行Shell命令的教程详解

    2024-04-25 15:10:51
  • vue+element-ui+sortable.js实现表格拖拽功能

    2024-04-09 11:00:11
  • Vue3 计算属性的用法详解

    2024-04-28 09:20:33
  • python编程测试电脑开启最大线程数实例代码

    2023-07-07 12:19:46
  • 学会这个炫酷图表利器pyecharts,还怕不被公司重用?

    2023-01-16 23:33:39
  • python 实时遍历日志文件

    2021-03-30 09:26:20
  • asp之家 网络编程 m.aspxhome.com