Golang 配置文件熱加載
通常我們更新應用程序的配置文件,都需要手動重啓程序或手動重新加載配置。重啓服務會造成服務的短暫不可以用。所以我們要實現配置文件的熱加載。實現這個的主要思路就是監聽這個配置文件是否有改動
主要實現代碼如下
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
"os"
"sync"
"time"
)
// Config 用json配置測試
type Config struct {
filename string
lastModifyTime int64
Key string `json:"key"`
}
var (
config *Config
configLock = new(sync.RWMutex)
)
func (config *Config) reload() {
// 定時器
ticker := time.NewTicker(time.Second * 5)
for range ticker.C {
// 打開文件
func() {
f, err := os.Open(GetConfig().filename)
if err != nil {
fmt.Printf("open file error:%s\n", err)
return
}
defer f.Close()
fileInfo, err := f.Stat()
if err != nil {
fmt.Printf("stat file error:%s\n", err)
return
}
// 或取當前文件修改時間
curModifyTime := fileInfo.ModTime().Unix()
if curModifyTime > GetConfig().lastModifyTime {
// 重新解析時,要考慮應用程序正在讀取這個配置因此應該加鎖
// 使用了 configLock 全局鎖
fmt.Print("cfg change, load new cfg\n")
loadConfig()
GetConfig().lastModifyTime = curModifyTime
}
}()
}
}
func loadConfig() bool {
fmt.Print("load cfg\n")
f, err := ioutil.ReadFile(config.filename)
if err != nil {
fmt.Println("load config error: ", err)
return false
}
//不同的配置規則,解析複雜度不同
temp := new(Config)
err = json.Unmarshal(f, &temp)
if err != nil {
fmt.Println("Para config failed: ", err)
return false
}
temp.filename = GetConfig().filename
temp.lastModifyTime = GetConfig().lastModifyTime
fmt.Printf("now cfg:%#v\n", temp)
configLock.Lock()
config = temp
configLock.Unlock()
return true
}
// GetConfig ...
func GetConfig() *Config {
configLock.RLock()
defer configLock.RUnlock()
return config
}
func init() {
config = new(Config)
config.filename = "config.json"
if !loadConfig() {
os.Exit(1)
}
//熱更新配置可能有多種觸發方式,這裏使用定時器實現
go config.reload()
}
func main() {
ticker := time.NewTicker(time.Second * 1)
for range ticker.C {
fmt.Printf("key:%s\n", GetConfig().Key)
}
}