github.com/galamsiva2020/kubernetes-heapster-monitoring@v0.0.0-20210823134957-3c1baa7c1e70/events/sinks/manager.go (about) 1 // Copyright 2015 Google Inc. All Rights Reserved. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package sinks 16 17 import ( 18 "sync" 19 "time" 20 21 "github.com/golang/glog" 22 "github.com/prometheus/client_golang/prometheus" 23 "k8s.io/heapster/events/core" 24 ) 25 26 const ( 27 DefaultSinkExportEventsTimeout = 20 * time.Second 28 DefaultSinkStopTimeout = 60 * time.Second 29 ) 30 31 var ( 32 // Time spent exporting events to sink in milliseconds. 33 exporterDuration = prometheus.NewSummaryVec( 34 prometheus.SummaryOpts{ 35 Namespace: "eventer", 36 Subsystem: "exporter", 37 Name: "duration_milliseconds", 38 Help: "Time spent exporting events to sink in milliseconds.", 39 }, 40 []string{"exporter"}, 41 ) 42 ) 43 44 func init() { 45 prometheus.MustRegister(exporterDuration) 46 } 47 48 type sinkHolder struct { 49 sink core.EventSink 50 eventBatchChannel chan *core.EventBatch 51 stopChannel chan bool 52 } 53 54 // Sink Manager - a special sink that distributes data to other sinks. It pushes data 55 // only to these sinks that completed their previous exports. Data that could not be 56 // pushed in the defined time is dropped and not retried. 57 type sinkManager struct { 58 sinkHolders []sinkHolder 59 exportEventsTimeout time.Duration 60 // Should be larger than exportEventsTimeout, although it is not a hard requirement. 61 stopTimeout time.Duration 62 } 63 64 func NewEventSinkManager(sinks []core.EventSink, exportEventsTimeout, stopTimeout time.Duration) (core.EventSink, error) { 65 sinkHolders := []sinkHolder{} 66 for _, sink := range sinks { 67 sh := sinkHolder{ 68 sink: sink, 69 eventBatchChannel: make(chan *core.EventBatch), 70 stopChannel: make(chan bool), 71 } 72 sinkHolders = append(sinkHolders, sh) 73 go func(sh sinkHolder) { 74 for { 75 select { 76 case data := <-sh.eventBatchChannel: 77 export(sh.sink, data) 78 case isStop := <-sh.stopChannel: 79 glog.V(2).Infof("Stop received: %s", sh.sink.Name()) 80 if isStop { 81 sh.sink.Stop() 82 return 83 } 84 } 85 } 86 }(sh) 87 } 88 return &sinkManager{ 89 sinkHolders: sinkHolders, 90 exportEventsTimeout: exportEventsTimeout, 91 stopTimeout: stopTimeout, 92 }, nil 93 } 94 95 // Guarantees that the export will complete in exportEventsTimeout. 96 func (this *sinkManager) ExportEvents(data *core.EventBatch) { 97 var wg sync.WaitGroup 98 for _, sh := range this.sinkHolders { 99 wg.Add(1) 100 go func(sh sinkHolder, wg *sync.WaitGroup) { 101 defer wg.Done() 102 glog.V(2).Infof("Pushing events to: %s", sh.sink.Name()) 103 select { 104 case sh.eventBatchChannel <- data: 105 glog.V(2).Infof("Data events completed: %s", sh.sink.Name()) 106 // everything ok 107 case <-time.After(this.exportEventsTimeout): 108 glog.Warningf("Failed to events data to sink: %s", sh.sink.Name()) 109 } 110 }(sh, &wg) 111 } 112 // Wait for all pushes to complete or timeout. 113 wg.Wait() 114 } 115 116 func (this *sinkManager) Name() string { 117 return "Manager" 118 } 119 120 func (this *sinkManager) Stop() { 121 for _, sh := range this.sinkHolders { 122 glog.V(2).Infof("Running stop for: %s", sh.sink.Name()) 123 124 go func(sh sinkHolder) { 125 select { 126 case sh.stopChannel <- true: 127 // everything ok 128 glog.V(2).Infof("Stop sent to sink: %s", sh.sink.Name()) 129 130 case <-time.After(this.stopTimeout): 131 glog.Warningf("Failed to stop sink: %s", sh.sink.Name()) 132 } 133 return 134 }(sh) 135 } 136 } 137 138 func export(s core.EventSink, data *core.EventBatch) { 139 startTime := time.Now() 140 defer func() { 141 exporterDuration. 142 WithLabelValues(s.Name()). 143 Observe(float64(time.Since(startTime)) / float64(time.Millisecond)) 144 }() 145 s.ExportEvents(data) 146 }