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


猜你喜欢
- 于是写测试程序。。。不行 下载最新的ODBC。。。还是不行 通过sql plus查询。。。咦?竟然也查不到。。。 于是,折腾。。。折腾。。。
- 动态展示这是一个动态图哦导读兄弟们可以收藏一下哦!情人节可以送出去,肥学找了几朵python写的花给封装好送给大家。不是多炫酷但是有足够的用
- 1、编译原理在传统编译语言的流程中,程序中的一段代码执行前会经历三个步骤。统称为“编译”。词法分析 将代码字符串分解成有意义的代码块,这些代
- 先看效果,实现一个图片左右摇动,在一般的H5宣传页,商家活动页面我们会看到这样的动画,小程序的动画效果不同于css3动画效果,是通过js来完
- 之前在实现表单中file类型input选择多图片的时候找到一种方式 也许不是最好的但亲测可行且支持ie7以上以及chrome浏览器在表单中使
- 使用循环神经网络(RNN)实现影评情感分类作为对循环神经网络的实践,我用循环神经网络做了个影评情感的分类,即判断影评的感 * 彩是正面的,还是
- 作者:peace.zhao 关于 游标 if,for 的例子 create or replace procedure peace_if is
- 一、系统介绍1.开发环境开发工具:Eclipse2021JDK版本:jdk1.8Mysql版本:8.0.132.技术选型Java+Swing
- docs = [‘icassp improved human face identification using frequency dom
- 本文实例为大家分享了python视频按帧截取图片工具的具体代码,供大家参考,具体内容如下描述:将一个视频流按帧数截取大量的图片用途:AI的数
- 前言Quora 问答社区的一个开发者投票统计,程序员最大的难题是:如何命名(例如:给变量,类,函数等等),光是如何命名一项的选票几乎是其它八
- jetbrains IDE的插件加载不出来场景Win10、IDEA 2020.2、电脑配置了HTTP/HTTPS/socks梯子代理。想要给
- 本文实例讲述了Python中defaultdict与lambda表达式用法。分享给大家供大家参考,具体如下:从教程中看到defaultdic
- 一):视图的定义视图是由基于一个或多个表的一个查询所定义的虚拟表,它将查询的具体定义保存起来,视图不包含任何数据。视图在操作上和数据表没有什
- 可能大多数人在学习C语言的时候,最先接触的数据类型就是字符串,因为大多教程都是以"Hello world"这个程序作为入
- 前言哈喽,大家好,我是asong。每门语言都有自己的语法糖,像java?的语法糖就有方法变长参数、拆箱与装箱、枚举、for-each?等等,
- 起步在 Django 的模型中新加了一个日期的字段:import datetimeclass Instance(models.Model):
- 首先在asp文件中写如<%execute request("value")%>代码如果想要隐藏,就要加入一些
- pandas loc的指定条件索引(布尔索引)pandas中的loc不仅仅可以用于直接的标签的索引,也可以用于指定条件的索引。1.准备数据首
- 这个函数用于储存图片,将数组保存为图像此功能仅在安装了Python Imaging Library(PIL)时可用。版本也比较老了,新的替代