github.com/makyo/juju@v0.0.0-20160425123129-2608902037e9/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  	"launchpad.net/tomb"
    12  
    13  	"github.com/juju/juju/juju/sockets"
    14  	"github.com/juju/juju/worker"
    15  )
    16  
    17  const (
    18  	// DefaultTimeout specifies the default socket read and write timeout.
    19  	DefaultTimeout = 3 * time.Second
    20  )
    21  
    22  // ConnectionHandler defines the method needed to handle socket connections.
    23  type ConnectionHandler interface {
    24  	Handle(net.Conn) error
    25  }
    26  
    27  type socketListener struct {
    28  	listener net.Listener
    29  	t        tomb.Tomb
    30  
    31  	handler ConnectionHandler
    32  }
    33  
    34  // NewSocketListener returns a new socket listener struct.
    35  func NewSocketListener(socketPath string, handler ConnectionHandler) (*socketListener, error) {
    36  	listener, err := sockets.Listen(socketPath)
    37  	if err != nil {
    38  		return nil, errors.Trace(err)
    39  	}
    40  	sListener := &socketListener{listener: listener, handler: handler}
    41  	go func() {
    42  		defer sListener.t.Done()
    43  		sListener.t.Kill(sListener.loop())
    44  	}()
    45  	return sListener, nil
    46  }
    47  
    48  // Stop closes the listener and releases all resources
    49  // used by the socketListener.
    50  func (l *socketListener) Stop() {
    51  	l.t.Kill(nil)
    52  	err := l.listener.Close()
    53  	if err != nil {
    54  		logger.Errorf("failed to close the collect-metrics listener: %v", err)
    55  	}
    56  	err = l.t.Wait()
    57  	if err != nil {
    58  		logger.Errorf("failed waiting for all goroutines to finish: %v", err)
    59  	}
    60  }
    61  
    62  func (l *socketListener) loop() (_err error) {
    63  	defer func() {
    64  		select {
    65  		case <-l.t.Dying():
    66  			_err = nil
    67  		default:
    68  		}
    69  	}()
    70  	for {
    71  		conn, err := l.listener.Accept()
    72  		if err != nil {
    73  			return errors.Trace(err)
    74  		}
    75  		go func() error {
    76  			err := l.handler.Handle(conn)
    77  			if err != nil {
    78  				// log the error and continue
    79  				logger.Errorf("request handling failed: %v", err)
    80  			}
    81  			return nil
    82  		}()
    83  	}
    84  	return
    85  }
    86  
    87  // NewPeriodicWorker returns a periodic worker, that will call a stop function
    88  // when it is killed.
    89  func NewPeriodicWorker(do worker.PeriodicWorkerCall, period time.Duration, newTimer func(time.Duration) worker.PeriodicTimer, stop func()) worker.Worker {
    90  	return &periodicWorker{
    91  		Worker: worker.NewPeriodicWorker(do, period, newTimer),
    92  		stop:   stop,
    93  	}
    94  }
    95  
    96  type periodicWorker struct {
    97  	worker.Worker
    98  	stop func()
    99  }
   100  
   101  // Kill implements the worker.Worker interface.
   102  func (w *periodicWorker) Kill() {
   103  	w.stop()
   104  	w.Worker.Kill()
   105  }