Ubuntu Pastebin

Paste from dfc at Tue, 9 Feb 2016 03:34:11 +0000

Download as text
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
diff --git a/apiserver/apiserver.go b/apiserver/apiserver.go
index 5de6940..ae08d21 100644
--- a/apiserver/apiserver.go
+++ b/apiserver/apiserver.go
@@ -50,6 +50,7 @@ type Server struct {
 	mongoUnavailable  uint32 // non zero if mongoUnavailable
 	modelUUID         string
 	authCtxt          *authContext
+	connections       int32 // count of active websocket connections
 }
 
 // LoginValidator functions are used to decide whether login requests
@@ -233,15 +234,20 @@ type requestNotifier struct {
 
 	mu   sync.Mutex
 	tag_ string
+
+	// count is incremented by calls to join, and deincremented
+	// by calls to leave.
+	count *int32
 }
 
 var globalCounter int64
 
-func newRequestNotifier() *requestNotifier {
+func newRequestNotifier(count *int32) *requestNotifier {
 	return &requestNotifier{
 		id:    atomic.AddInt64(&globalCounter, 1),
 		tag_:  "<unknown>",
 		start: time.Now(),
+		count: count,
 	}
 }
 
@@ -287,11 +293,13 @@ func (n *requestNotifier) ServerReply(req rpc.Request, hdr *rpc.Header, body int
 }
 
 func (n *requestNotifier) join(req *http.Request) {
-	logger.Infof("[%X] API connection from %s", n.id, req.RemoteAddr)
+	active := atomic.AddInt32(n.count, 1)
+	logger.Infof("[%X] API connection from %s, active connections: %d", n.id, req.RemoteAddr, active)
 }
 
 func (n *requestNotifier) leave() {
-	logger.Infof("[%X] %s API connection terminated after %v", n.id, n.tag(), time.Since(n.start))
+	active := atomic.AddInt32(n.count, -1)
+	logger.Infof("[%X] %s API connection terminated after %v, active connections: %d", n.id, n.tag(), time.Since(n.start), active)
 }
 
 func (n *requestNotifier) ClientRequest(hdr *rpc.Header, body interface{}) {
@@ -312,6 +320,12 @@ func handleAll(mux *pat.PatternServeMux, pattern string, handler http.Handler) {
 func (srv *Server) run() {
 	logger.Infof("listening on %q", srv.lis.Addr())
 	defer func() {
+		addr := srv.lis.Addr().String() // Addr not valid after close
+		err := srv.lis.Close()
+		logger.Infof("closed listening socket %q with final error: %v", addr, err)
+	}()
+
+	defer func() {
 		srv.state.HackLeadership() // Break deadlocks caused by BlockUntil... calls.
 		srv.wg.Wait()              // wait for any outstanding requests to complete.
 		srv.tomb.Done()
@@ -402,16 +416,20 @@ func (srv *Server) run() {
 	handleAll(mux, "/", http.HandlerFunc(srv.apiHandler))
 
 	go func() {
-		// The error from http.Serve is not interesting.
-		http.Serve(srv.lis, mux)
+		addr := srv.list.Addr() // not valid after addr closed
+		log.Infof("Starting API http server on address %q", addr)
+		err := http.Serve(srv.lis, mux)
+		// normally logging an error at debug level would be grounds for a beating,
+		// however in this case the error is *expected* to be non nil, and does not
+		// affect the operation of the apiserver, but for completeness log it anyway.
+		log.Infof("API http server exited, final error was: %v", err)
 	}()
 
 	<-srv.tomb.Dying()
-	srv.lis.Close()
 }
 
 func (srv *Server) apiHandler(w http.ResponseWriter, req *http.Request) {
-	reqNotifier := newRequestNotifier()
+	reqNotifier := newRequestNotifier(&srv.connections)
 	reqNotifier.join(req)
 	defer reqNotifier.leave()
 	wsServer := websocket.Server{
Download as text