首页  >  文章  >  后端开发  >  如何设计一个能够优雅地处理更新和错误的配置缓存?

如何设计一个能够优雅地处理更新和错误的配置缓存?

Mary-Kate Olsen
Mary-Kate Olsen原创
2024-10-25 06:43:02722浏览

How to Design a Configuration Cache That Handles Updates and Errors Gracefully?

从文件加载配置并使用新更新刷新

问题陈述:

代码设计涉及在启动时从文件加载配置并定期使用新版本刷新它。目标是建立一种处理以下要求的机制:

  • 对配置的并发访问
  • 重新加载检测到的配置更改
  • 对最新配置的可访问性
  • 更新期间立即访问最新配置
  • 更新失败时保留以前的配置

初始设计利用并发映射来存储配置,但面临更新过程中的错误可能导致地图为空的问题。

解决方案:

提出了一个简化的设计来满足所有要求:

CustomerConfig 结构:

定义要缓存的配置:

type CustomerConfig struct {
    Data map[string]bool
    LoadedAt time.Time
}

loadConfig 函数:

加载文件中的配置:

func loadConfig() (*CustomerConfig, error) {
    cfg := &CustomerConfig{
        Data:     map[string]bool{},
        LoadedAt: time.Now(),
    }

    // Logic to load files and populate cfg.Data
    // If an error occurs, return it

    // If loading succeeds, return the config
    return cfg, nil
}

ConfigCache 结构:

管理配置缓存:

type ConfigCache struct {
    configMu sync.RWMutex
    config   *CustomerConfig
    closeCh  chan struct{}
}

NewConfigCache 函数:

创建新的配置缓存:

func NewConfigCache() (*ConfigCache, error) {
    cfg, err := loadConfig()
    if err != nil {
        return nil, fmt.Errorf("loading initial config failed: %w", err)
    }

    cc := &ConfigCache{
        config:  cfg,
        closeCh: make(chan struct{}),
    }

    // Launch a goroutine to periodically check for changes and load new configs
    go cc.refresher()

    return cc, nil
}

刷新功能:

定期检查配置更改并更新缓存:

func (cc *ConfigCache) refresher() {
    ticker := time.NewTicker(1 * time.Minute) // Every minute
    defer ticker.Stop()

    for {
        select {
        case <-ticker.C:
            // Check for changes
            changes := false // Logic to detect changes
            if !changes {
                continue // No changes, continue
            }

            // Changes! Load new config:
            cfg, err := loadConfig()
            if err != nil {
                log.Printf("Failed to load config: %v", err)
                continue // Keep the previous config
            }

            // Apply / store new config
            cc.configMu.Lock()
            cc.config = cfg
            cc.configMu.Unlock()

        case <-cc.closeCh:
            return
        }
    }
}

停止函数:

停止复习 goroutine:

func (cc *ConfigCache) Stop() {
    close(cc.closeCh)
}

GetConfig 函数:

访问当前配置:

func (cc *ConfigCache) GetConfig() *CustomerConfig {
    cc.configMu.RLock()
    defer cc.configMu.RUnlock()
    return cc.config
}

用法:

cc, err := NewConfigCache()
if err != nil {
    // Handle the error appropriately
}

// Access the configuration whenever needed:
cfg := cc.GetConfig()
// Use the configuration here

// Stop the cache refreshing when necessary:
cc.Stop()

此解决方案确保:

  • 并发访问配置
  • 检测到更改时重新加载
  • 可访问最新配置
  • 更新期间可立即访问
  • 更新失败时保留以前的配置

以上是如何设计一个能够优雅地处理更新和错误的配置缓存?的详细内容。更多信息请关注PHP中文网其他相关文章!

声明:
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn