github.com/axw/juju@v0.0.0-20161005053422-4bd6544d08d4/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/tomb.v1"
    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, <-chan struct{}) 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() error {
    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  	return l.t.Wait()
    57  }
    58  
    59  func (l *socketListener) loop() error {
    60  	for {
    61  		conn, err := l.listener.Accept()
    62  		if err != nil {
    63  			return errors.Trace(err)
    64  		}
    65  		go func() {
    66  			err := l.handler.Handle(conn, l.t.Dying())
    67  			if err != nil {
    68  				// log the error and continue
    69  				logger.Errorf("request handling failed: %v", err)
    70  			}
    71  		}()
    72  	}
    73  }
    74  
    75  // NewPeriodicWorker returns a periodic worker, that will call a stop function
    76  // when it is killed.
    77  func NewPeriodicWorker(do worker.PeriodicWorkerCall, period time.Duration, newTimer func(time.Duration) worker.PeriodicTimer, stop func()) worker.Worker {
    78  	return &periodicWorker{
    79  		Worker: worker.NewPeriodicWorker(do, period, newTimer),
    80  		stop:   stop,
    81  	}
    82  }
    83  
    84  type periodicWorker struct {
    85  	worker.Worker
    86  	stop func()
    87  }
    88  
    89  // Kill implements the worker.Worker interface.
    90  func (w *periodicWorker) Kill() {
    91  	w.stop()
    92  	w.Worker.Kill()
    93  }