| 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) startConfigChangedPoller(c context.Context, hash string) { |
| 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.startConfigChangedPoller(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 |