Skip to content

Commit

Permalink
Ensure sig handler routine returns on shutdown, turn it off in most t…
Browse files Browse the repository at this point in the history
…ests

I noticed that when running the test suite, there would be a file
server/log1.txt left. This file is created by one of the config
reload test. Running this test individually was doing the proper
cleanup. I noticed that the Signal test that was checking
that files could be rotated was causing this side effect.
It turns out that none of the config reload tests were disabling
the signal handler (NoSigs=true), and since the go routine would
be left running, running the TestSignalToReOpenLogFile() test
would interact with an already finished test.

I put a thread dump in handleSignals() to track all tests that
were causing this function to start the go routine because NoSigs
was not set to true. I fixed all those tests. At this time, there
are only 2 tests that need to start the signal handler.

I have also fixed the code so that the signal handler routine select
on a server quitCh that is closed on shutdown so that this go routine
exit and is waiting on using the grWG wait group.
  • Loading branch information
kozlovic committed Apr 6, 2018
1 parent e8b524a commit 40cf010
Show file tree
Hide file tree
Showing 8 changed files with 43 additions and 24 deletions.
1 change: 1 addition & 0 deletions server/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -698,6 +698,7 @@ func TestTLSCloseClientConnection(t *testing.T) {
}
opts.TLSTimeout = 100
opts.NoLog = true
opts.NoSigs = true
s := RunServer(opts)
defer s.Shutdown()

Expand Down
4 changes: 2 additions & 2 deletions server/reload.go
Original file line number Diff line number Diff line change
Expand Up @@ -570,8 +570,8 @@ func (s *Server) diffOptions(newOpts *Options) ([]option, error) {
}
}
diffOpts = append(diffOpts, &clientAdvertiseOption{newValue: cliAdv})
case "nolog":
// Ignore NoLog option since it's not parsed and only used in
case "nolog", "nosigs":
// Ignore NoLog ad NoSigs options since they are not parsed and only used in
// testing.
continue
case "port":
Expand Down
12 changes: 11 additions & 1 deletion server/reload_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ import (
// Ensure Reload returns an error when attempting to reload a server that did
// not start with a config file.
func TestConfigReloadNoConfigFile(t *testing.T) {
server := New(&Options{})
server := New(&Options{NoSigs: true})
loaded := server.ConfigTime()
if server.Reload() == nil {
t.Fatal("Expected Reload to return an error")
Expand Down Expand Up @@ -69,6 +69,7 @@ func TestConfigReloadUnsupported(t *testing.T) {
Host: "localhost",
Port: -1,
},
NoSigs: true,
}
processOptions(golden)

Expand Down Expand Up @@ -158,6 +159,7 @@ func TestConfigReloadInvalidConfig(t *testing.T) {
Host: "localhost",
Port: -1,
},
NoSigs: true,
}
processOptions(golden)

Expand Down Expand Up @@ -224,6 +226,7 @@ func TestConfigReload(t *testing.T) {
Host: "localhost",
Port: server.ClusterAddr().Port,
},
NoSigs: true,
}
processOptions(golden)

Expand Down Expand Up @@ -1306,6 +1309,7 @@ func TestConfigReloadClusterRoutes(t *testing.T) {
t.Fatalf("Error processing config file: %v", err)
}
srvcOpts.NoLog = true
srvcOpts.NoSigs = true

srvc := RunServer(srvcOpts)
defer srvc.Shutdown()
Expand Down Expand Up @@ -1410,6 +1414,7 @@ func TestConfigReloadClusterAdvertise(t *testing.T) {
t.Fatalf("Error processing config file: %v", err)
}
opts.NoLog = true
opts.NoSigs = true
s := RunServer(opts)
defer s.Shutdown()

Expand Down Expand Up @@ -1491,6 +1496,7 @@ func TestConfigReloadClusterNoAdvertise(t *testing.T) {
t.Fatalf("Error processing config file: %v", err)
}
opts.NoLog = true
opts.NoSigs = true
s := RunServer(opts)
defer s.Shutdown()

Expand Down Expand Up @@ -1545,6 +1551,7 @@ func TestConfigReloadClientAdvertise(t *testing.T) {
stackFatalf(t, "Error processing config file: %v", err)
}
opts.NoLog = true
opts.NoSigs = true
s := RunServer(opts)
defer s.Shutdown()

Expand Down Expand Up @@ -1767,11 +1774,13 @@ func TestConfigReloadRotateFiles(t *testing.T) {
func runServerWithSymlinkConfig(t *testing.T, symlinkName, configName string) (*Server, *Options, string) {
opts, config := newOptionsWithSymlinkConfig(t, symlinkName, configName)
opts.NoLog = true
opts.NoSigs = true
return RunServer(opts), opts, config
}

func newServerWithSymlinkConfig(t *testing.T, symlinkName, configName string) (*Server, *Options, string) {
opts, config := newOptionsWithSymlinkConfig(t, symlinkName, configName)
opts.NoSigs = true
return New(opts), opts, config
}

Expand All @@ -1786,6 +1795,7 @@ func newOptionsWithSymlinkConfig(t *testing.T, symlinkName, configName string) (
if err != nil {
t.Fatalf("Error processing config file: %v", err)
}
opts.NoSigs = true
return opts, config
}

Expand Down
2 changes: 1 addition & 1 deletion server/route.go
Original file line number Diff line number Diff line change
Expand Up @@ -812,7 +812,7 @@ func (s *Server) connectToRoute(rURL *url.URL, tryForEver bool) {
}
}
select {
case <-s.rcQuit:
case <-s.quitCh:
return
case <-time.After(DEFAULT_ROUTE_CONNECT):
continue
Expand Down
1 change: 1 addition & 0 deletions server/routes_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -542,6 +542,7 @@ func TestTLSChainedSolicitWorks(t *testing.T) {
func TestRouteTLSHandshakeError(t *testing.T) {
optsSeed, _ := ProcessConfigFile("./configs/seed_tls.conf")
optsSeed.NoLog = true
optsSeed.NoSigs = true
srvSeed := RunServer(optsSeed)
defer srvSeed.Shutdown()

Expand Down
12 changes: 6 additions & 6 deletions server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ type Server struct {
routeListener net.Listener
routeInfo Info
routeInfoJSON []byte
rcQuit chan bool
quitCh chan struct{}
grMu sync.Mutex
grTmpClients map[uint64]*client
grRunning bool
Expand Down Expand Up @@ -173,9 +173,9 @@ func New(opts *Options) *Server {
s.routes = make(map[uint64]*client)
s.remotes = make(map[string]*client)

// Used to kick out all of the route
// connect Go routines.
s.rcQuit = make(chan bool)
// Used to kick out all go routines possibly waiting on server
// to shutdown.
s.quitCh = make(chan struct{})

// Used to setup Authorization.
s.configureAuthorization()
Expand Down Expand Up @@ -381,8 +381,8 @@ func (s *Server) Shutdown() {
s.profiler.Close()
}

// Release the solicited routes connect go routines.
close(s.rcQuit)
// Release go routines that wait on that channel
close(s.quitCh)

s.mu.Unlock()

Expand Down
33 changes: 20 additions & 13 deletions server/signal.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,21 +37,28 @@ func (s *Server) handleSignals() {

signal.Notify(c, syscall.SIGINT, syscall.SIGUSR1, syscall.SIGHUP)

s.grWG.Add(1)
go func() {
for sig := range c {
s.Debugf("Trapped %q signal", sig)
switch sig {
case syscall.SIGINT:
s.Noticef("Server Exiting..")
os.Exit(0)
case syscall.SIGUSR1:
// File log re-open for rotating file logs.
s.ReOpenLogFile()
case syscall.SIGHUP:
// Config reload.
if err := s.Reload(); err != nil {
s.Errorf("Failed to reload server configuration: %s", err)
defer s.grWG.Done()
for {
select {
case sig := <-c:
s.Debugf("Trapped %q signal", sig)
switch sig {
case syscall.SIGINT:
s.Noticef("Server Exiting..")
os.Exit(0)
case syscall.SIGUSR1:
// File log re-open for rotating file logs.
s.ReOpenLogFile()
case syscall.SIGHUP:
// Config reload.
if err := s.Reload(); err != nil {
s.Errorf("Failed to reload server configuration: %s", err)
}
}
case <-s.quitCh:
return
}
}
}()
Expand Down
2 changes: 1 addition & 1 deletion test/port_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import (
)

func TestResolveRandomPort(t *testing.T) {
opts := &server.Options{Host: "127.0.0.1", Port: server.RANDOM_PORT}
opts := &server.Options{Host: "127.0.0.1", Port: server.RANDOM_PORT, NoSigs: true}
s := RunServer(opts)
defer s.Shutdown()

Expand Down

0 comments on commit 40cf010

Please sign in to comment.