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  }