github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/worker/remoterelations/remoterelationsworker.go (about) 1 // Copyright 2017 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package remoterelations 5 6 import ( 7 "sync" 8 "time" 9 10 "github.com/juju/names/v5" 11 "github.com/juju/worker/v3" 12 "github.com/juju/worker/v3/catacomb" 13 14 "github.com/juju/juju/core/watcher" 15 "github.com/juju/juju/rpc/params" 16 ) 17 18 // remoteRelationsWorker listens for changes to the 19 // life and status of a relation in the offering model. 20 type remoteRelationsWorker struct { 21 catacomb catacomb.Catacomb 22 23 mu sync.Mutex 24 25 // mostRecentEvent is stored here for the engine report. 26 mostRecentEvent RelationUnitChangeEvent 27 changeSince time.Time 28 29 relationTag names.RelationTag 30 remoteRelationToken string 31 applicationToken string 32 relationsWatcher watcher.RelationStatusWatcher 33 changes chan<- RelationUnitChangeEvent 34 logger Logger 35 } 36 37 func newRemoteRelationsWorker( 38 relationTag names.RelationTag, 39 applicationToken string, 40 remoteRelationToken string, 41 relationsWatcher watcher.RelationStatusWatcher, 42 changes chan<- RelationUnitChangeEvent, 43 logger Logger, 44 ) (*remoteRelationsWorker, error) { 45 w := &remoteRelationsWorker{ 46 relationsWatcher: relationsWatcher, 47 relationTag: relationTag, 48 remoteRelationToken: remoteRelationToken, 49 applicationToken: applicationToken, 50 changes: changes, 51 logger: logger, 52 } 53 err := catacomb.Invoke(catacomb.Plan{ 54 Site: &w.catacomb, 55 Work: w.loop, 56 Init: []worker.Worker{relationsWatcher}, 57 }) 58 return w, err 59 } 60 61 // Kill is defined on worker.Worker 62 func (w *remoteRelationsWorker) Kill() { 63 w.catacomb.Kill(nil) 64 } 65 66 // Wait is defined on worker.Worker 67 func (w *remoteRelationsWorker) Wait() error { 68 err := w.catacomb.Wait() 69 if err != nil { 70 w.logger.Errorf("error in remote relations worker for relation %v: %v", w.relationTag.Id(), err) 71 } 72 return err 73 } 74 75 func (w *remoteRelationsWorker) loop() error { 76 var ( 77 changes chan<- RelationUnitChangeEvent 78 event RelationUnitChangeEvent 79 ) 80 for { 81 select { 82 case <-w.catacomb.Dying(): 83 return w.catacomb.ErrDying() 84 85 case relChanges, ok := <-w.relationsWatcher.Changes(): 86 if !ok { 87 // We are dying. 88 return w.catacomb.ErrDying() 89 } 90 if len(relChanges) == 0 { 91 w.logger.Warningf("relation status watcher event with no changes") 92 continue 93 } 94 // We only care about the most recent change. 95 change := relChanges[len(relChanges)-1] 96 w.logger.Debugf("relation status changed for %v: %v", w.relationTag, change) 97 suspended := change.Suspended 98 w.mu.Lock() 99 w.mostRecentEvent = RelationUnitChangeEvent{ 100 Tag: w.relationTag, 101 RemoteRelationChangeEvent: params.RemoteRelationChangeEvent{ 102 RelationToken: w.remoteRelationToken, 103 ApplicationToken: w.applicationToken, 104 Life: change.Life, 105 Suspended: &suspended, 106 SuspendedReason: change.SuspendedReason, 107 }, 108 } 109 w.changeSince = time.Now() 110 event = w.mostRecentEvent 111 w.mu.Unlock() 112 changes = w.changes 113 114 case changes <- event: 115 changes = nil 116 } 117 } 118 } 119 120 // Report provides information for the engine report. 121 func (w *remoteRelationsWorker) Report() map[string]interface{} { 122 result := make(map[string]interface{}) 123 w.mu.Lock() 124 defer w.mu.Unlock() 125 126 if w.mostRecentEvent.Tag.Id() != "" { 127 result["life"] = w.mostRecentEvent.Life 128 result["suspended"] = w.mostRecentEvent.Suspended 129 result["since"] = w.changeSince.Format(time.RFC1123Z) 130 } 131 132 return result 133 }