github.com/kaisenlinux/docker.io@v0.0.0-20230510090727-ea55db55fac7/swarmkit/watch/sinks.go (about)

     1  package watch
     2  
     3  import (
     4  	"fmt"
     5  	"time"
     6  
     7  	events "github.com/docker/go-events"
     8  )
     9  
    10  // ErrSinkTimeout is returned from the Write method when a sink times out.
    11  var ErrSinkTimeout = fmt.Errorf("timeout exceeded, tearing down sink")
    12  
    13  // timeoutSink is a sink that wraps another sink with a timeout. If the
    14  // embedded sink fails to complete a Write operation within the specified
    15  // timeout, the Write operation of the timeoutSink fails.
    16  type timeoutSink struct {
    17  	timeout time.Duration
    18  	sink    events.Sink
    19  }
    20  
    21  func (s timeoutSink) Write(event events.Event) error {
    22  	errChan := make(chan error)
    23  	go func(c chan<- error) {
    24  		c <- s.sink.Write(event)
    25  	}(errChan)
    26  
    27  	timer := time.NewTimer(s.timeout)
    28  	select {
    29  	case err := <-errChan:
    30  		timer.Stop()
    31  		return err
    32  	case <-timer.C:
    33  		s.sink.Close()
    34  		return ErrSinkTimeout
    35  	}
    36  }
    37  
    38  func (s timeoutSink) Close() error {
    39  	return s.sink.Close()
    40  }
    41  
    42  // dropErrClosed is a sink that suppresses ErrSinkClosed from Write, to avoid
    43  // debug log messages that may be confusing. It is possible that the queue
    44  // will try to write an event to its destination channel while the queue is
    45  // being removed from the broadcaster. Since the channel is closed before the
    46  // queue, there is a narrow window when this is possible. In some event-based
    47  // dropping events when a sink is removed from a broadcaster is a problem, but
    48  // for the usage in this watch package that's the expected behavior.
    49  type dropErrClosed struct {
    50  	sink events.Sink
    51  }
    52  
    53  func (s dropErrClosed) Write(event events.Event) error {
    54  	err := s.sink.Write(event)
    55  	if err == events.ErrSinkClosed {
    56  		return nil
    57  	}
    58  	return err
    59  }
    60  
    61  func (s dropErrClosed) Close() error {
    62  	return s.sink.Close()
    63  }
    64  
    65  // dropErrClosedChanGen is a ChannelSinkGenerator for dropErrClosed sinks wrapping
    66  // unbuffered channels.
    67  type dropErrClosedChanGen struct{}
    68  
    69  func (s *dropErrClosedChanGen) NewChannelSink() (events.Sink, *events.Channel) {
    70  	ch := events.NewChannel(0)
    71  	return dropErrClosed{sink: ch}, ch
    72  }
    73  
    74  // TimeoutDropErrChanGen is a ChannelSinkGenerator that creates a channel,
    75  // wrapped by the dropErrClosed sink and a timeout.
    76  type TimeoutDropErrChanGen struct {
    77  	timeout time.Duration
    78  }
    79  
    80  // NewChannelSink creates a new sink chain of timeoutSink->dropErrClosed->Channel
    81  func (s *TimeoutDropErrChanGen) NewChannelSink() (events.Sink, *events.Channel) {
    82  	ch := events.NewChannel(0)
    83  	return timeoutSink{
    84  		timeout: s.timeout,
    85  		sink: dropErrClosed{
    86  			sink: ch,
    87  		},
    88  	}, ch
    89  }
    90  
    91  // NewTimeoutDropErrSinkGen returns a generator of timeoutSinks wrapping dropErrClosed
    92  // sinks, wrapping unbuffered channel sinks.
    93  func NewTimeoutDropErrSinkGen(timeout time.Duration) ChannelSinkGenerator {
    94  	return &TimeoutDropErrChanGen{timeout: timeout}
    95  }