首页 > 其他分享 >golang中使用原子操作监听配置更新

golang中使用原子操作监听配置更新

时间:2022-12-29 16:57:36浏览次数:60  
标签:string nil 原子 golang json cond file 监听 configValue

配置及代码文件

{
    "name":"sasuke",
    "age":25,
    "gender":"male",
    "score":99.5
}
develop.json
package main

import (
    "crypto/md5"
    "encoding/hex"
    "encoding/json"
    "fmt"
    "io"
    "os"
    "sync"
    "sync/atomic"
    "time"
)

type Student struct {
    Name   string  `json:"name"`
    Age    int     `json:"age"`
    Gender string  `json:"gender"`
    Score  float32 `json:"score"`
}

// 声明一个全局的变量,存放上一次文件变更时文件的hash值
var lastFileHash string = ""

// 生命一个全局的结构体对象配置,项目中使用这个全局变量,在业务中使用
var StudentConfig *Student

// 获取配置的值
func loadConfig(filePath string) (*Student, error) {
    file, errFile := os.Open(filePath)
    if errFile != nil {
        return nil, errFile
    }

    defer file.Close()

    //NewDecoder创建一个从file读取并解码json对象的*Decoder,解码器有自己的缓冲,并可能超前读取部分json数据。
    decoder := json.NewDecoder(file)

    conf := Student{}
    //Decode从输入流读取下一个json编码值并保存在v指向的值里
    errDecoder := decoder.Decode(&conf)
    if errDecoder != nil {
        return nil, errDecoder
    }

    return &conf, nil
}

// 获取文件的hash值
func getFileHash(filePath string) (string, error) {
    file, err := os.Open(filePath)
    if err != nil {
        return "", err
    }
    defer file.Close()

    m := md5.New()
    _, err = io.Copy(m, file)
    if err != nil {
        return "", err
    }

    return hex.EncodeToString(m.Sum(nil)), nil
}

// 每隔5秒校验一下配置文件有没有更新,更新的话就给监听的协裎发通知
func checkFileChanged(configValue *atomic.Value, cond *sync.Cond, filePath string) {

    for {
        time.Sleep(time.Second * 5)
        // 如果文件变更了,那么它的hash值会改变
        fileHash, errFileHash := getFileHash(filePath)
        if errFileHash != nil {
            // 打log、上报告警等...
            fmt.Println("errFileHash: ", errFileHash)
            continue
        }
        // 文件没有变更,不用管
        if fileHash == lastFileHash {
            continue
        }

        // 文件有变更
        // 因为只有一个协裎在用这个变量,所以不存在竞争问题,直接赋值就好
        lastFileHash = fileHash
        // 加载最新的配置
        newConf, errNewConf := loadConfig(filePath)
        if errNewConf != nil {
            // 打log、上报告警等...
            fmt.Println("errNewConf: ", errNewConf)
            continue
        }
        // fmt.Println("newConf: ", newConf)
        // atomoc.Value Store
        configValue.Store(newConf)
        // 通知:配置已变更
        cond.Broadcast()
    }
}

// 获取更新的配置,实际上可能有多个协裎在监听~
func loadConfigValue(configValue *atomic.Value, cond *sync.Cond) {
    for {
        cond.L.Lock()
        // 等待配置变更的信号
        cond.Wait()
        // 读取新的配置信息,并且复制给全局变量
        // s1 := configValue.Load()
        // fmt.Printf("s1: %T, %v \n", s1, s1)
        // Notice 注意这里要转化为 *Student
        StudentConfig = configValue.Load().(*Student)
        cond.L.Unlock()
    }
}

func main() {
    var configValue atomic.Value
    var cond = sync.NewCond(&sync.Mutex{})

    // Notice 注意在协裎中要使用同一个 atomic.Value 变量,所以需要传指针!

    // check & store & broadcast
    go checkFileChanged(&configValue, cond, "./develop.json")

    // listening & load
    go loadConfigValue(&configValue, cond)

    // 在主协裎打印一下最新的配置看看
    go func() {
        for {
            time.Sleep(time.Second * 2)
            fmt.Println("最新的配置:", StudentConfig)
        }
    }()

    select {}

}
main.go

参考文章

如何读取yaml,json,ini等配置文件

golang 计算字符以及文件的 hash 值

标签:string,nil,原子,golang,json,cond,file,监听,configValue
From: https://www.cnblogs.com/paulwhw/p/17012976.html

相关文章

  • zookeeper原子消息广播协议--ZAB
    ZAB协议是为分布式协调服务ZooKeeper专门设计的一种支持崩溃恢复的原子广播协议。在ZooKeeper中,主要依赖ZAB协议来实现分布式数据一致性,基于该协议,ZooKeeper实现了......
  • golang写入influxdb2,共3种方式,小心有坑!
    ==事件背景==项目中需要接收设备上报的时序数据,写入到Influxdb中,在压力测试过程中发现服务器CPU占用的非常高,使用pprof解析了CPU占用的详细信息之后,发现Influxdb的AddFie......
  • golang安装与vscode配置
     问题描述warning:GOPATHsettoGOROOT(D:\Golang\go\)hasnoeffect解决办法:go1.19.4.windows-amd64.msi安装在d:\Golang\go      ......
  • go-dongle 0.2.3 版本发布,一个轻量级、语义化的 golang 编码解码、加密解密库
    dongle是一个轻量级、语义化、对开发者友好的Golang编码解码和加密解密库Dongle已被awesome-go收录,如果您觉得不错,请给个star吧github.com/golang-module/dong......
  • Go-20 Golang 中go mod 和 golang包详解
    packagemainimport( "fmt" "github.com/shopspring/decimal")//Golang中的gomod以及Golang包详解funcmain(){ /* 1.初始化项目文件夹gomodinit文件......
  • MySQL的端口监听到tcp6
    问题描述mysql-uroot-P3308-p无法登陆  处理方式在my.cnf配置文件里面添加以下内容,然后重启MySQL服务。bind-address=0.0.0.0  然后就可以正常登陆......
  • GoLang初探
    简介     多核处理器越来越普及,那有没有一种简单的办法,能够让我们写的软件释放多核的威力?答案是:Yes。随着Golang,Erlang,Scale等为并发设计的程序语言的兴......
  • Golang中interface的使用建议
    https://medium.com/@mbinjamil/using-interfaces-in-go-the-right-way-99384bc69d39分享的是一个关于Golang中interface的正确使用方法。讲道理在medium上找一篇对我有......
  • Golang开发项目目录简介以及目录结构设置规范
    一、Golang项目简单介绍Golang简单的目录结构如下:其中,bin用来存放经过gobulid后的可执行文件,pkg存放编译后的gomodule,而src就存放我们项目的代码 二、三种常用目录结......
  • Golang 环境变量和项目结构
    1.Golang环境变量和项目结构常用exportGO_HOME=/opt/modules/goexportGOPATH=/home/user/go$GO_HOME/bin:$GOPATH/bin12341.1.为什么我使用gobuild命令没有没有......