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.
This commit is contained in:
Josh Rickmar 2014-01-14 22:53:07 -05:00
parent d8227c2751
commit bd98836a2b
2 changed files with 17 additions and 5 deletions

View file

@ -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
}

View file

@ -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 {