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 }