Skip to content

Small cleanup in App and Node #3962

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 18 additions & 23 deletions app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import (
"syscall"

"go.uber.org/zap"
"golang.org/x/sync/errgroup"

"github.com/ava-labs/avalanchego/node"
"github.com/ava-labs/avalanchego/utils"
Expand All @@ -34,16 +33,16 @@ var _ App = (*app)(nil)
type App interface {
// Start kicks off the application and returns immediately.
// Start should only be called once.
Start() error
Start()

// Stop notifies the application to exit and returns immediately.
// Stop should only be called after [Start].
// It is safe to call Stop multiple times.
Stop() error
Stop()

// ExitCode should only be called after [Start] returns with no error. It
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment should be updated

// should block until the application finishes
ExitCode() (int, error)
ExitCode() int
}

func New(config nodeconfig.Config) (App, error) {
Expand Down Expand Up @@ -89,9 +88,7 @@ func New(config nodeconfig.Config) (App, error) {

func Run(app App) int {
// start running the application
if err := app.Start(); err != nil {
return 1
}
app.Start()

// register terminationSignals to kill the application
terminationSignals := make(chan os.Signal, 1)
Expand All @@ -101,13 +98,15 @@ func Run(app App) int {
signal.Notify(stackTraceSignal, syscall.SIGABRT)

// start up a new go routine to handle attempts to kill the application
var eg errgroup.Group
eg.Go(func() error {
var wg sync.WaitGroup
wg.Add(1)
go func() {
defer wg.Done()
for range terminationSignals {
return app.Stop()
app.Stop()
return
}
return nil
})
}()

// start a goroutine to listen on SIGABRT signals,
// to print the stack trace to standard error.
Expand All @@ -118,7 +117,7 @@ func Run(app App) int {
}()

// wait for the app to exit and get the exit code response
exitCode, err := app.ExitCode()
exitCode := app.ExitCode()

// shut down the termination signal go routine
signal.Stop(terminationSignals)
Expand All @@ -129,9 +128,7 @@ func Run(app App) int {
close(stackTraceSignal)

// if there was an error closing or running the application, report that error
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment should be updated

if eg.Wait() != nil || err != nil {
return 1
}
wg.Wait()

// return the exit code that the application reported
return exitCode
Expand All @@ -148,7 +145,7 @@ type app struct {
// Start the business logic of the node (as opposed to config reading, etc).
// Does not block until the node is done. Errors returned from this method
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment is stale

// are not logged.
func (a *app) Start() error {
func (a *app) Start() {
// [p.ExitCode] will block until [p.exitWG.Done] is called
a.exitWG.Add(1)
go func() {
Expand All @@ -172,19 +169,17 @@ func (a *app) Start() error {
zap.Error(err),
)
}()
return nil
}

// Stop attempts to shutdown the currently running node. This function will
// return immediately.
func (a *app) Stop() error {
// block until shutdown is complete.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment change isn't really inaccurate (at least based on the intention of the original code).

Calling Shutdown(0) on the node doesn't actually block until shutdown finishes. Shutdown finishes when Dispatch() returns. Notice that Shutdown only starts the shutdown process.

func (a *app) Stop() {
a.node.Shutdown(0)
return nil
}

// ExitCode returns the exit code that the node is reporting. This function
// blocks until the node has been shut down.
func (a *app) ExitCode() (int, error) {
func (a *app) ExitCode() int {
a.exitWG.Wait()
return a.node.ExitCode(), nil
return a.node.ExitCode()
}
23 changes: 7 additions & 16 deletions node/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -134,8 +134,6 @@ func New(
Config: config,
}

n.DoneShuttingDown.Add(1)

pop, err := signer.NewProofOfPossession(n.Config.StakingSigningKey)
if err != nil {
return nil, fmt.Errorf("problem creating proof of possession: %w", err)
Expand Down Expand Up @@ -365,10 +363,6 @@ type Node struct {
// Sets the exit code
shuttingDownExitCode utils.Atomic[int]

// Incremented only once on initialization.
// Decremented when node is done shutting down.
DoneShuttingDown sync.WaitGroup

// Metrics Registerer
MetricsGatherer metrics.MultiGatherer
MeterDBMetricsGatherer metrics.MultiGatherer
Expand Down Expand Up @@ -682,7 +676,8 @@ func (n *Node) Dispatch() error {
)
}
// If the API server isn't running, shut down the node.
// If node is already shutting down, this does nothing.
// If node is already shutting down, this does not tigger shutdown again,
// and blocks until the shutdown is complete.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// and blocks until the shutdown is complete.
// and blocks until the shutdown returns.

n.Shutdown(1)
})

Expand Down Expand Up @@ -716,10 +711,11 @@ func (n *Node) Dispatch() error {
}

// Start P2P connections
err := n.Net.Dispatch()
retErr := n.Net.Dispatch()

// If the P2P server isn't running, shut down the node.
// If node is already shutting down, this does nothing.
// If node is already shutting down, this does not tigger shutdown again,
// and blocks until the shutdown is complete.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// and blocks until the shutdown is complete.
// and blocks until the shutdown returns.

n.Shutdown(1)

if n.tlsKeyLogWriterCloser != nil {
Expand All @@ -732,9 +728,6 @@ func (n *Node) Dispatch() error {
}
}

// Wait until the node is done shutting down before returning
n.DoneShuttingDown.Wait()

// Remove the process context file to communicate to an orchestrator
// that the node is no longer running.
if err := os.Remove(n.Config.ProcessContextFilePath); err != nil && !errors.Is(err, fs.ErrNotExist) {
Expand All @@ -744,7 +737,7 @@ func (n *Node) Dispatch() error {
)
}

return err
return retErr
}

/*
Expand Down Expand Up @@ -1629,10 +1622,9 @@ func (n *Node) initDiskTargeter(
// Shutdown this node
// May be called multiple times
func (n *Node) Shutdown(exitCode int) {
if !n.shuttingDown.Get() { // only set the exit code once
if !n.shuttingDown.Swap(true) { // only set the exit code once
n.shuttingDownExitCode.Set(exitCode)
}
n.shuttingDown.Set(true)
n.shutdownOnce.Do(n.shutdown)
}

Expand Down Expand Up @@ -1714,7 +1706,6 @@ func (n *Node) shutdown() {
)
}

n.DoneShuttingDown.Done()
n.Log.Info("finished node shutdown")
}

Expand Down
10 changes: 10 additions & 0 deletions utils/atomic.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,16 @@ func (a *Atomic[T]) Set(value T) {
a.value = value
}

func (a *Atomic[T]) Swap(value T) T {
a.lock.Lock()
defer a.lock.Unlock()

old := a.value
a.value = value

return old
}

func (a *Atomic[T]) MarshalJSON() ([]byte, error) {
a.lock.RLock()
defer a.lock.RUnlock()
Expand Down