github.com/Ilhicas/nomad@v1.0.4-0.20210304152020-e86851182bc3/client/pluginmanager/group.go (about) 1 package pluginmanager 2 3 import ( 4 "context" 5 "fmt" 6 "sync" 7 8 log "github.com/hashicorp/go-hclog" 9 ) 10 11 // PluginGroup is a utility struct to manage a collectively orchestrate a 12 // set of PluginManagers 13 type PluginGroup struct { 14 // managers is the set of managers managed, access is synced by mLock 15 managers []PluginManager 16 17 // shutdown indicates if shutdown has been called, access is synced by mLock 18 shutdown bool 19 20 // mLock gaurds managers and shutdown 21 mLock sync.Mutex 22 23 logger log.Logger 24 } 25 26 // New returns an initialized PluginGroup 27 func New(logger log.Logger) *PluginGroup { 28 return &PluginGroup{ 29 managers: []PluginManager{}, 30 logger: logger.Named("plugin"), 31 } 32 } 33 34 // RegisterAndRun registers the manager and starts it in a separate goroutine 35 func (m *PluginGroup) RegisterAndRun(manager PluginManager) error { 36 m.mLock.Lock() 37 defer m.mLock.Unlock() 38 if m.shutdown { 39 return fmt.Errorf("plugin group already shutdown") 40 } 41 m.managers = append(m.managers, manager) 42 43 m.logger.Info("starting plugin manager", "plugin-type", manager.PluginType()) 44 manager.Run() 45 return nil 46 } 47 48 // Ready returns a channel which will be closed once all plugin managers are ready. 49 // A timeout for waiting on each manager is given 50 func (m *PluginGroup) WaitForFirstFingerprint(ctx context.Context) (<-chan struct{}, error) { 51 m.mLock.Lock() 52 defer m.mLock.Unlock() 53 if m.shutdown { 54 return nil, fmt.Errorf("plugin group already shutdown") 55 } 56 57 var wg sync.WaitGroup 58 for i := range m.managers { 59 manager, ok := m.managers[i].(FingerprintingPluginManager) 60 if !ok { 61 continue 62 } 63 logger := m.logger.With("plugin-type", manager.PluginType()) 64 wg.Add(1) 65 go func() { 66 defer wg.Done() 67 logger.Debug("waiting on plugin manager initial fingerprint") 68 69 select { 70 case <-manager.WaitForFirstFingerprint(ctx): 71 logger.Debug("finished plugin manager initial fingerprint") 72 case <-ctx.Done(): 73 logger.Warn("timeout waiting for plugin manager to be ready") 74 } 75 }() 76 } 77 78 ret := make(chan struct{}) 79 go func() { 80 wg.Wait() 81 close(ret) 82 }() 83 return ret, nil 84 } 85 86 // Shutdown shutsdown all registered PluginManagers in reverse order of how 87 // they were started. 88 func (m *PluginGroup) Shutdown() { 89 m.mLock.Lock() 90 defer m.mLock.Unlock() 91 for i := len(m.managers) - 1; i >= 0; i-- { 92 m.logger.Info("shutting down plugin manager", "plugin-type", m.managers[i].PluginType()) 93 m.managers[i].Shutdown() 94 m.logger.Info("plugin manager finished", "plugin-type", m.managers[i].PluginType()) 95 } 96 m.shutdown = true 97 }