github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/worker/metrics/spool/listener.go (about)

     1  // Copyright 2016 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package spool
     5  
     6  import (
     7  	"net"
     8  	"time"
     9  
    10  	"github.com/juju/errors"
    11  	"gopkg.in/juju/worker.v1"
    12  	"gopkg.in/tomb.v2"
    13  
    14  	"github.com/juju/juju/juju/sockets"
    15  	jworker "github.com/juju/juju/worker"
    16  )
    17  
    18  const (
    19  	// DefaultTimeout specifies the default socket read and write timeout.
    20  	DefaultTimeout = 3 * time.Second
    21  )
    22  
    23  // ConnectionHandler defines the method needed to handle socket connections.
    24  type ConnectionHandler interface {
    25  	Handle(net.Conn, <-chan struct{}) error
    26  }
    27  
    28  type socketListener struct {
    29  	listener net.Listener
    30  	t        tomb.Tomb
    31  
    32  	handler ConnectionHandler
    33  }
    34  
    35  // NewSocketListener returns a new socket listener struct.
    36  func NewSocketListener(socketPath string, handler ConnectionHandler) (*socketListener, error) {
    37  	listener, err := sockets.Listen(socketPath)
    38  	if err != nil {
    39  		return nil, errors.Trace(err)
    40  	}
    41  	sListener := &socketListener{listener: listener, handler: handler}
    42  	sListener.t.Go(sListener.loop)
    43  	return sListener, nil
    44  }
    45  
    46  // Stop closes the listener and releases all resources
    47  // used by the socketListener.
    48  func (l *socketListener) Stop() error {
    49  	l.t.Kill(nil)
    50  	err := l.listener.Close()
    51  	if err != nil {
    52  		logger.Errorf("failed to close the collect-metrics listener: %v", err)
    53  	}
    54  	return l.t.Wait()
    55  }
    56  
    57  func (l *socketListener) loop() error {
    58  	for {
    59  		conn, err := l.listener.Accept()
    60  		if err != nil {
    61  			return errors.Trace(err)
    62  		}
    63  		go func() {
    64  			err := l.handler.Handle(conn, l.t.Dying())
    65  			if err != nil {
    66  				// log the error and continue
    67  				logger.Errorf("request handling failed: %v", err)
    68  			}
    69  		}()
    70  	}
    71  }
    72  
    73  // NewPeriodicWorker returns a periodic worker, that will call a stop function
    74  // when it is killed.
    75  func NewPeriodicWorker(do jworker.PeriodicWorkerCall, period time.Duration, newTimer func(time.Duration) jworker.PeriodicTimer, stop func()) worker.Worker {
    76  	return &periodicWorker{
    77  		Worker: jworker.NewPeriodicWorker(do, period, newTimer, jworker.Jitter(0.2)),
    78  		stop:   stop,
    79  	}
    80  }
    81  
    82  type periodicWorker struct {
    83  	worker.Worker
    84  	stop func()
    85  }
    86  
    87  // Kill implements the worker.Worker interface.
    88  func (w *periodicWorker) Kill() {
    89  	w.stop()
    90  	w.Worker.Kill()
    91  }