From bd98836a2b7525c93e7b3b60d9732e13c28e36eb Mon Sep 17 00:00:00 2001 From: Josh Rickmar Date: Tue, 14 Jan 2014 22:53:07 -0500 Subject: [PATCH] Fix several bugs in the RPC server shutdown. The RPC server was performing some of the shutdown logic in the wrong order, that is, logging the the server has shut down, waiting for all server goroutines to finish, and then closing a channel to notify server goroutines to stop. These three items have been reversed to fix a hang where goroutines currently being waited on had not shut down because they did not receive the notification. While here, the server waitgroup was incremented for a goroutine that was running without it, another select statement was added to stop a duplicate close (which never occured last commit when I added the select statements), and the "stopping rescan" logging was moved to debug to make the ^C shutdown logging nicer. --- rpcserver.go | 7 +++++-- rpcwebsocket.go | 15 ++++++++++++--- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/rpcserver.go b/rpcserver.go index 6450b1363..5247c97f4 100644 --- a/rpcserver.go +++ b/rpcserver.go @@ -147,7 +147,10 @@ func (s *rpcServer) Start() { w.Header().Set("Connection", "close") jsonRPCRead(w, r, s) }) + + s.wg.Add(1) go s.walletListenerDuplicator() + rpcServeMux.HandleFunc("/wallet", func(w http.ResponseWriter, r *http.Request) { if err := s.checkAuth(r); err != nil { http.Error(w, "401 Unauthorized.", http.StatusUnauthorized) @@ -203,9 +206,9 @@ func (s *rpcServer) Stop() error { return err } } - rpcsLog.Infof("RPC server shutdown complete") - s.wg.Wait() close(s.quit) + s.wg.Wait() + rpcsLog.Infof("RPC server shutdown complete") return nil } diff --git a/rpcwebsocket.go b/rpcwebsocket.go index 1f3e2a91e..5d714c6cc 100644 --- a/rpcwebsocket.go +++ b/rpcwebsocket.go @@ -367,7 +367,7 @@ func handleRescan(s *rpcServer, icmd btcjson.Cmd, c handlerChans) (interface{}, // client requesting the rescan has disconnected. select { case <-c.disconnected: - rpcsLog.Infof("Stopping rescan at height %v for disconnected client", + rpcsLog.Debugf("Stopping rescan at height %v for disconnected client", blk.Height()) return nil, nil @@ -518,6 +518,7 @@ func (s *rpcServer) RemoveWalletListener(n ntfnChan) { func (s *rpcServer) walletListenerDuplicator() { // Duplicate all messages sent across walletNotificationMaster to each // listening wallet. +out: for { select { case ntfn := <-s.ws.walletNotificationMaster: @@ -528,9 +529,11 @@ func (s *rpcServer) walletListenerDuplicator() { s.ws.RUnlock() case <-s.quit: - return + break out } } + + s.wg.Done() } // walletReqsNotifications is the handler function for websocket @@ -587,7 +590,13 @@ func (s *rpcServer) walletReqsNotifications(ws *websocket.Conn) { case <-s.quit: // Server closed. Closing disconnected signals handlers to stop // and flushes all channels handlers may write to. - close(disconnected) + select { + case <-disconnected: + // nothing + + default: + close(disconnected) + } case <-disconnected: for {