Go语言实现配置热加载的方法分享
作者:tracy小猫 发布时间:2024-02-07 04:02:47
标签:Go,配置,热加载
概述
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
2. 修改config ,port为9903
来源:https://juejin.cn/post/7185563516094316600
0
投稿
猜你喜欢
- 配置要求:IIS(win2000 server 自带)、Java 2 SDK 1.4.2 (或更高版本)、Tomcat Web Server
- 问题在做web端ui层自动化的时候会碰到文件上传的操作,经常有朋友问到,这里总结一下解决方案第一种:type=file的上传文件,类似如下的
- floor() 函数向下舍入为最接近的整数。语法floor(x)参数描述x必需。一个数。说明返回不大于 x 的下一个整数
- 本文实例讲述了Python常见工厂函数用法。分享给大家供大家参考,具体如下:工厂函数:能够产生类实例的内建函数。 工厂函数是指这些
- PIL:Python Imaging Library,已经是Python平台事实上的图像处理标准库了。PIL功能非常强大,但API却非常简单
- 单向链表单向链表也叫单链表,是链表中最简单的一种形式,它的每个节点包含两个域,一个信息域(元素域)和一个链接域。这个链接指向链表中的下一个节
- 本文实例为大家分享了mysql 5.7.13 winx64安装配置方法图文教程,供大家参考,具体内容如下(1) 下载MySQL程序,您可以从
- 今天模拟定义map函数.写着写着就发现Python可变长度参数的机制真是灵活而强大.假设有一个元组t,包含n个成员:t=(arg1,...,
- 目录寻找 url下载视频执行代码下载:最后的话回答来源微信 8.0 版本更新后,可以设置个人状态,状态里面可以添加火录制视频,很快状态视频就
- pyinstaller打包配置文件无法正常读取import osfile = os.path.dirname(os.path.abspath
- 目录引入依赖配置构建实体类保存数据查询数据项目中需要存放大量设备日志,且需要对其进行简单的数据分析,信息提取工作.结合众多考量因素,项目决定
- datetime模块用于是date和time模块的合集,datetime有两个常量,MAXYEAR和MINYEAR,分别是9999和1.da
- 本文实例讲述了Mysql数据库中数据表的优化、外键与三范式用法。分享给大家供大家参考,具体如下:数据表优化将商品信息表进行优化1.创建商品种
- 【摘要】 性能 首先,FCKEDITOR的性能是非常好的,用户只需很少的时间就可以载入FCKEDITOR所需文件.对于其他在线编辑器来说,这
- 项目开发一直在docker的虚拟环境上,遇到了一个问题,就是把虚拟环境的包删掉(rm -rf xxx)之后,再重新拷贝一个(跟原来包一模一样
- 由于工作需要本文主结合了excel表格,对表格中的ssh密码进行批量修改以下是详细代码(python3):'''遇到
- 本文实例讲述了MySQL Union合并查询数据及表别名、字段别名用法。分享给大家供大家参考,具体如下:union关键字SELECT s_i
- 1.’%.2f’%f该方法会进行四舍五入代码如下所示:f = 2.3456789print('
- “操作入口明确”,就是指产品的任何一个功能都要有明确、合理的入口。“操作入口”,指的是产品内部不同模块之间的转接元素,例如在Web产品中,按
- GUID(Global unique identifier)全局唯一标识符,它是由网卡上的标识数字(每个网卡都有唯一的标