Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 package config | |
| 6 | |
| 7 import ( | |
| 8 "time" | |
| 9 | |
| 10 "github.com/golang/protobuf/proto" | |
| 11 "github.com/luci/luci-go/common/clock" | |
| 12 "github.com/luci/luci-go/common/config" | |
| 13 log "github.com/luci/luci-go/common/logging" | |
| 14 "github.com/luci/luci-go/common/proto/logdog/svcconfig" | |
| 15 "golang.org/x/net/context" | |
| 16 ) | |
| 17 | |
| 18 // Options is the set of options used to set up a Manager. | |
| 19 // | |
| 20 // The configuration is loaded from a svcconfig.Config protobuf. | |
| 21 type Options struct { | |
| 22 // Config is the configuration service to load from. | |
| 23 Config config.Interface | |
| 24 | |
| 25 // ConfigSet is the name of the ConfigSet to load. | |
| 26 ConfigSet string | |
| 27 // ConfigPath is the name of the ConfigPath to load. | |
| 28 ConfigPath string | |
| 29 | |
| 30 // KillFunc, if not nil, will be called if a configuration change has be en | |
| 31 // detected. | |
| 32 KillFunc func() | |
| 33 | |
| 34 // KillCheckInterval, if >0, starts a goroutine that polls every interva l to | |
| 35 // see if the configuration has changed. If it has, KillFunc will be inv oked. | |
| 36 KillCheckInterval time.Duration | |
| 37 } | |
| 38 | |
| 39 func (o *Options) startKillPoller(c context.Context, hash string) { | |
|
iannucci
2016/01/28 01:15:35
isn't this actually a config poller that happens t
dnj
2016/01/29 20:46:52
Yes? I named it this b/c it's polling to kill, but
| |
| 40 for { | |
| 41 log.Fields{ | |
| 42 "timeout": o.KillCheckInterval, | |
| 43 }.Debugf(c, "Entering kill check poll loop...") | |
| 44 | |
| 45 select { | |
| 46 case <-c.Done(): | |
| 47 log.WithError(c.Err()).Debugf(c, "Context cancelled, shu tting down kill poller.") | |
| 48 return | |
| 49 | |
| 50 case <-clock.After(c, o.KillCheckInterval): | |
| 51 log.Infof(c, "Kill check timeout triggered, reloading co nfiguration...") | |
| 52 | |
| 53 cfg, err := o.getConfig(true) | |
| 54 if err != nil { | |
| 55 log.WithError(err).Warningf(c, "Failed to reload configuration.") | |
| 56 continue | |
| 57 } | |
| 58 | |
| 59 if cfg.ContentHash != hash { | |
| 60 log.Fields{ | |
| 61 "currentHash": hash, | |
| 62 "newHash": cfg.ContentHash, | |
| 63 }.Errorf(c, "Configuration content hash has chan ged.") | |
| 64 o.runKillFunc() | |
| 65 return | |
| 66 } | |
| 67 | |
| 68 log.Fields{ | |
| 69 "currentHash": hash, | |
| 70 }.Debugf(c, "Content hash matches.") | |
| 71 } | |
| 72 } | |
| 73 } | |
| 74 | |
| 75 func (o *Options) runKillFunc() { | |
| 76 if o.KillFunc != nil { | |
| 77 o.KillFunc() | |
| 78 } | |
| 79 } | |
| 80 | |
| 81 func (o *Options) getConfig(hashOnly bool) (*config.Config, error) { | |
| 82 return o.Config.GetConfig(o.ConfigSet, o.ConfigPath, hashOnly) | |
| 83 } | |
| 84 | |
| 85 // Manager holds and exposes a service configuration. | |
| 86 // | |
| 87 // It can also periodically refresh that configuration and invoke a shutdown | |
| 88 // function if its content changes. | |
| 89 type Manager struct { | |
| 90 o *Options | |
| 91 | |
| 92 cfg *svcconfig.Config | |
| 93 contentHash string | |
| 94 } | |
| 95 | |
| 96 // NewManager generates a new Manager and loads the initial configuration. | |
| 97 func NewManager(c context.Context, o Options) (*Manager, error) { | |
| 98 m := Manager{ | |
| 99 o: &o, | |
| 100 } | |
| 101 | |
| 102 // Load the initial configuration. | |
| 103 if err := m.reloadConfig(c); err != nil { | |
| 104 return nil, err | |
| 105 } | |
| 106 | |
| 107 if o.KillCheckInterval > 0 { | |
| 108 go m.o.startKillPoller(c, m.contentHash) | |
| 109 } | |
| 110 | |
| 111 return &m, nil | |
| 112 } | |
| 113 | |
| 114 // Config returns the service configuration instance. | |
| 115 func (m *Manager) Config() *svcconfig.Config { | |
| 116 return m.cfg | |
| 117 } | |
| 118 | |
| 119 func (m *Manager) reloadConfig(c context.Context) error { | |
| 120 cfg, err := m.o.getConfig(false) | |
| 121 if err != nil { | |
| 122 return err | |
| 123 } | |
| 124 | |
| 125 scfg := svcconfig.Config{} | |
| 126 if err := proto.UnmarshalText(cfg.Content, &scfg); err != nil { | |
| 127 log.Fields{ | |
| 128 log.ErrorKey: err, | |
| 129 "hash": cfg.ContentHash, | |
| 130 }.Errorf(c, "Failed to unmarshal configuration.") | |
| 131 return err | |
| 132 } | |
| 133 | |
| 134 m.cfg = &scfg | |
| 135 m.contentHash = cfg.ContentHash | |
| 136 return nil | |
| 137 } | |
| OLD | NEW |