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 }