Skip to content
Merged
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
5 changes: 3 additions & 2 deletions daemon/algod/api/server/lib/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,9 @@ type Routes []Route
// ReqContext is passed to each of the handlers below via wrapCtx, allowing
// handlers to interact with the node
type ReqContext struct {
Node *node.AlgorandFullNode
Log logging.Logger
Node *node.AlgorandFullNode
Log logging.Logger
Shutdown <-chan struct{}
}

// ErrorResponse sets the specified status code (should != 200), and fills in the
Expand Down
4 changes: 2 additions & 2 deletions daemon/algod/api/server/router.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ func registerHandlers(router *mux.Router, prefix string, routes lib.Routes, ctx
}

// NewRouter builds and returns a new router from routes
func NewRouter(logger logging.Logger, node *node.AlgorandFullNode, apiToken string) *mux.Router {
func NewRouter(logger logging.Logger, node *node.AlgorandFullNode, shutdown <-chan struct{}, apiToken string) *mux.Router {
router := mux.NewRouter().StrictSlash(true)

// Middleware
Expand All @@ -115,7 +115,7 @@ func NewRouter(logger logging.Logger, node *node.AlgorandFullNode, apiToken stri
router.Use(middlewares.CORS)

// Request Context
ctx := lib.ReqContext{Node: node, Log: logger}
ctx := lib.ReqContext{Node: node, Log: logger, Shutdown: shutdown}

// Registers /debug/pprof handler under root path and under /urlAuth path
// to support header or url-provided token.
Expand Down
1 change: 1 addition & 0 deletions daemon/algod/api/server/v1/handlers/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,5 +40,6 @@ var (
errNoRoundsSpecified = "Indexer is not enabled, firstRound and lastRound must be specified"
errNoTxnSpecified = "no transaction ID was specified"
errTransactionNotFound = "couldn't find the required transaction in the required range"
errServiceShuttingDown = "operation aborted as server is shutting down"
errUnknownTransactionType = "found a transaction with an unknown type"
)
3 changes: 3 additions & 0 deletions daemon/algod/api/server/v1/handlers/handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -419,6 +419,9 @@ func WaitForBlock(ctx lib.ReqContext, w http.ResponseWriter, r *http.Request) {
}

select {
Comment thread
algonautshant marked this conversation as resolved.
case <-ctx.Shutdown:
lib.ErrorResponse(w, http.StatusInternalServerError, err, errServiceShuttingDown, ctx.Log)
return
case <-time.After(1 * time.Minute):
case <-ctx.Node.Ledger().Wait(basics.Round(queryRound + 1)):
}
Expand Down
42 changes: 18 additions & 24 deletions daemon/algod/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,7 @@ type Server struct {
node *node.AlgorandFullNode
metricCollector *metrics.MetricService
metricServiceStarted bool

stopping deadlock.Mutex
stopped bool
stopping chan struct{}
}

// Initialize creates a Node instance with applicable network services
Expand Down Expand Up @@ -178,9 +176,11 @@ func (s *Server) Start() {
os.Exit(1)
}

s.stopping = make(chan struct{})

// use the data dir as the static file dir (for our API server), there's
// no need to separate the two yet. This lets us serve the swagger.json file.
apiHandler := apiServer.NewRouter(s.log, s.node, apiToken)
apiHandler := apiServer.NewRouter(s.log, s.node, s.stopping, apiToken)

addr := cfg.EndpointAddress
if addr == "" {
Expand All @@ -202,8 +202,6 @@ func (s *Server) Start() {
WriteTimeout: time.Duration(cfg.RestWriteTimeoutSeconds) * time.Second,
}

defer s.Stop()

tcpListener := listener.(*net.TCPListener)
errChan := make(chan error, 1)
go func() {
Expand All @@ -227,30 +225,28 @@ func (s *Server) Start() {
c := make(chan os.Signal)
signal.Notify(c, os.Interrupt, syscall.SIGTERM, syscall.SIGINT)
signal.Ignore(syscall.SIGHUP)
go func() {
sig := <-c

fmt.Printf("Node running and accepting RPC requests over HTTP on port %v. Press Ctrl-C to exit\n", addr)
select {
case err := <-errChan:
if err != nil {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

errChan name is giving the impression that only errors will trigger this case.
However, this case is triggered when the server returns.
Maybe rename errChan to serverReturn?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I will look into that in a subsequent PR.

s.log.Warn(err)
} else {
s.log.Info("Node exited successfully")
}
s.Stop()
case sig := <-c:
fmt.Printf("Exiting on %v\n", sig)
s.Stop()
os.Exit(0)
}()

fmt.Printf("Node running and accepting RPC requests over HTTP on port %v. Press Ctrl-C to exit\n", addr)
err = <-errChan
if err != nil {
s.log.Warn(err)
} else {
s.log.Info("Node exited successfully")
}
}

// Stop initiates a graceful shutdown of the node by shutting down the network server.
func (s *Server) Stop() {
s.stopping.Lock()
defer s.stopping.Unlock()

if s.stopped {
return
}
// close the s.stopping, which would signal the rest api router that any pending commands
// should be aborted.
close(s.stopping)
Comment thread
tsachiherman marked this conversation as resolved.

// Attempt to log a shutdown event before we exit...
s.log.Event(telemetryspec.ApplicationState, telemetryspec.ShutdownEvent)
Expand All @@ -275,8 +271,6 @@ func (s *Server) Stop() {
os.Remove(s.pidFile)
os.Remove(s.netFile)
os.Remove(s.netListenFile)

s.stopped = true
}

// OverridePhonebook is used to replace the phonebook associated with
Expand Down