Merge pull request #7614 from yyforyongyu/fix-pprof-err
lntest+lnd: gracefully shutdown pprof server
This commit is contained in:
3 files changed
+46
-18
No files matched your search
@@ -180,14 +180,42 @@ func Main(cfg *Config, lisCfg ListenerCfg, implCfg *ImplementationCfg,
|
|||||||
network,
|
network,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
ctx := context.Background()
|
||||||
|
ctx, cancel := context.WithCancel(ctx)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
// Enable http profiling server if requested.
|
// Enable http profiling server if requested.
|
||||||
if cfg.Profile != "" {
|
if cfg.Profile != "" {
|
||||||
|
// Create the http handler.
|
||||||
|
profileRedirect := http.RedirectHandler(
|
||||||
|
"/debug/pprof", http.StatusSeeOther,
|
||||||
|
)
|
||||||
|
http.Handle("/", profileRedirect)
|
||||||
|
ltndLog.Infof("Pprof listening on %v", cfg.Profile)
|
||||||
|
|
||||||
|
// Create the pprof server.
|
||||||
|
pprofServer := &http.Server{
|
||||||
|
Addr: cfg.Profile,
|
||||||
|
Handler: profileRedirect,
|
||||||
|
ReadHeaderTimeout: 5 * time.Second,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Shut the server down when lnd is shutting down.
|
||||||
|
defer func() {
|
||||||
|
ltndLog.Info("Stopping pprof server...")
|
||||||
|
err := pprofServer.Shutdown(ctx)
|
||||||
|
if err != nil {
|
||||||
|
ltndLog.Errorf("Stop pprof server got err: %v",
|
||||||
|
err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
// Start the pprof server.
|
||||||
go func() {
|
go func() {
|
||||||
profileRedirect := http.RedirectHandler("/debug/pprof",
|
err := pprofServer.ListenAndServe()
|
||||||
http.StatusSeeOther)
|
if err != nil && !errors.Is(err, http.ErrServerClosed) {
|
||||||
http.Handle("/", profileRedirect)
|
ltndLog.Errorf("Serving pprof got err: %v", err)
|
||||||
ltndLog.Infof("Pprof listening on %v", cfg.Profile)
|
}
|
||||||
fmt.Println(http.ListenAndServe(cfg.Profile, nil))
|
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -202,10 +230,6 @@ func Main(cfg *Config, lisCfg ListenerCfg, implCfg *ImplementationCfg,
|
|||||||
defer pprof.StopCPUProfile()
|
defer pprof.StopCPUProfile()
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx := context.Background()
|
|
||||||
ctx, cancel := context.WithCancel(ctx)
|
|
||||||
defer cancel()
|
|
||||||
|
|
||||||
// Run configuration dependent DB pre-initialization. Note that this
|
// Run configuration dependent DB pre-initialization. Note that this
|
||||||
// needs to be done early and once during the startup process, before
|
// needs to be done early and once during the startup process, before
|
||||||
// any DB access.
|
// any DB access.
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import (
|
|||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
@@ -627,10 +628,12 @@ func (hn *HarnessNode) cleanup() error {
|
|||||||
|
|
||||||
// waitForProcessExit Launch a new goroutine which that bubbles up any
|
// waitForProcessExit Launch a new goroutine which that bubbles up any
|
||||||
// potential fatal process errors to the goroutine running the tests.
|
// potential fatal process errors to the goroutine running the tests.
|
||||||
func (hn *HarnessNode) waitForProcessExit() {
|
func (hn *HarnessNode) waitForProcessExit() error {
|
||||||
|
var err error
|
||||||
|
|
||||||
errChan := make(chan error, 1)
|
errChan := make(chan error, 1)
|
||||||
go func() {
|
go func() {
|
||||||
err := hn.cmd.Wait()
|
err = hn.cmd.Wait()
|
||||||
errChan <- err
|
errChan <- err
|
||||||
}()
|
}()
|
||||||
|
|
||||||
@@ -643,7 +646,7 @@ func (hn *HarnessNode) waitForProcessExit() {
|
|||||||
// If the process has already been canceled, we can exit early
|
// If the process has already been canceled, we can exit early
|
||||||
// as the logs have already been saved.
|
// as the logs have already been saved.
|
||||||
if strings.Contains(err.Error(), "Wait was already called") {
|
if strings.Contains(err.Error(), "Wait was already called") {
|
||||||
return
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Otherwise, we print the error, break the select and save
|
// Otherwise, we print the error, break the select and save
|
||||||
@@ -653,7 +656,8 @@ func (hn *HarnessNode) waitForProcessExit() {
|
|||||||
break
|
break
|
||||||
|
|
||||||
case <-time.After(wait.DefaultTimeout):
|
case <-time.After(wait.DefaultTimeout):
|
||||||
hn.printErrf("timeout waiting for process to exit")
|
err = errors.New("timeout waiting for process to exit")
|
||||||
|
hn.printErrf(err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure log file is closed and renamed if necessary.
|
// Make sure log file is closed and renamed if necessary.
|
||||||
@@ -662,6 +666,8 @@ func (hn *HarnessNode) waitForProcessExit() {
|
|||||||
// Rename the etcd.log file if the node was running on embedded
|
// Rename the etcd.log file if the node was running on embedded
|
||||||
// etcd.
|
// etcd.
|
||||||
finalizeEtcdLog(hn)
|
finalizeEtcdLog(hn)
|
||||||
|
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stop attempts to stop the active lnd process.
|
// Stop attempts to stop the active lnd process.
|
||||||
@@ -675,9 +681,6 @@ func (hn *HarnessNode) Stop() error {
|
|||||||
// Stop the runCtx.
|
// Stop the runCtx.
|
||||||
hn.cancel()
|
hn.cancel()
|
||||||
|
|
||||||
// Wait for lnd process to exit in the end.
|
|
||||||
defer hn.waitForProcessExit()
|
|
||||||
|
|
||||||
// If we ever reaches the state where `Watcher` is initialized, it
|
// If we ever reaches the state where `Watcher` is initialized, it
|
||||||
// means the node has an authed connection and all its RPC clients are
|
// means the node has an authed connection and all its RPC clients are
|
||||||
// ready for use. Thus we will try to stop it via the RPC.
|
// ready for use. Thus we will try to stop it via the RPC.
|
||||||
@@ -740,7 +743,8 @@ func (hn *HarnessNode) Stop() error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
// Wait for lnd process to exit in the end.
|
||||||
|
return hn.waitForProcessExit()
|
||||||
}
|
}
|
||||||
|
|
||||||
// CloseConn closes the grpc connection.
|
// CloseConn closes the grpc connection.
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ const (
|
|||||||
|
|
||||||
// ChannelCloseTimeout is the max time we will wait before a channel is
|
// ChannelCloseTimeout is the max time we will wait before a channel is
|
||||||
// considered closed.
|
// considered closed.
|
||||||
ChannelCloseTimeout = time.Second * 30
|
ChannelCloseTimeout = time.Second * 60
|
||||||
|
|
||||||
// DefaultTimeout is a timeout that will be used for various wait
|
// DefaultTimeout is a timeout that will be used for various wait
|
||||||
// scenarios where no custom timeout value is defined.
|
// scenarios where no custom timeout value is defined.
|
||||||
|
|||||||
Reference in new issue
Block a user