github.com/timstclair/heapster@v0.20.0-alpha1/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 "k8s.io/heapster/events/core" 23 ) 24 25 const ( 26 DefaultSinkExportEventsTimeout = 20 * time.Second 27 DefaultSinkStopTimeout = 60 * time.Second 28 ) 29 30 type sinkHolder struct { 31 sink core.EventSink 32 eventBatchChannel chan *core.EventBatch 33 stopChannel chan bool 34 } 35 36 // Sink Manager - a special sink that distributes data to other sinks. It pushes data 37 // only to these sinks that completed their previous exports. Data that could not be 38 // pushed in the defined time is dropped and not retried. 39 type sinkManager struct { 40 sinkHolders []sinkHolder 41 exportEventsTimeout time.Duration 42 // Should be larger than exportEventsTimeout, although it is not a hard requirement. 43 stopTimeout time.Duration 44 } 45 46 func NewEventSinkManager(sinks []core.EventSink, exportEventsTimeout, stopTimeout time.Duration) (core.EventSink, error) { 47 sinkHolders := []sinkHolder{} 48 for _, sink := range sinks { 49 sh := sinkHolder{ 50 sink: sink, 51 eventBatchChannel: make(chan *core.EventBatch), 52 stopChannel: make(chan bool), 53 } 54 sinkHolders = append(sinkHolders, sh) 55 go func(sh sinkHolder) { 56 for { 57 select { 58 case data := <-sh.eventBatchChannel: 59 sh.sink.ExportEvents(data) 60 case isStop := <-sh.stopChannel: 61 glog.V(2).Infof("Stop received: %s", sh.sink.Name()) 62 if isStop { 63 sh.sink.Stop() 64 return 65 } 66 } 67 } 68 }(sh) 69 } 70 return &sinkManager{ 71 sinkHolders: sinkHolders, 72 exportEventsTimeout: exportEventsTimeout, 73 stopTimeout: stopTimeout, 74 }, nil 75 } 76 77 // Guarantees that the export will complete in exportEventsTimeout. 78 func (this *sinkManager) ExportEvents(data *core.EventBatch) { 79 var wg sync.WaitGroup 80 for _, sh := range this.sinkHolders { 81 wg.Add(1) 82 go func(sh sinkHolder, wg *sync.WaitGroup) { 83 defer wg.Done() 84 glog.V(2).Infof("Pushing events to: %s", sh.sink.Name()) 85 select { 86 case sh.eventBatchChannel <- data: 87 glog.V(2).Infof("Data events completed: %s", sh.sink.Name()) 88 // everything ok 89 case <-time.After(this.exportEventsTimeout): 90 glog.Warningf("Failed to events data to sink: %s", sh.sink.Name()) 91 } 92 }(sh, &wg) 93 } 94 // Wait for all pushes to complete or timeout. 95 wg.Wait() 96 } 97 98 func (this *sinkManager) Name() string { 99 return "Manager" 100 } 101 102 func (this *sinkManager) Stop() { 103 for _, sh := range this.sinkHolders { 104 glog.V(2).Infof("Running stop for: %s", sh.sink.Name()) 105 106 go func(sh sinkHolder) { 107 select { 108 case sh.stopChannel <- true: 109 // everything ok 110 glog.V(2).Infof("Stop sent to sink: %s", sh.sink.Name()) 111 112 case <-time.After(this.stopTimeout): 113 glog.Warningf("Failed to stop sink: %s", sh.sink.Name()) 114 } 115 return 116 }(sh) 117 } 118 }