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  }