Skip to content
Snippets Groups Projects
Unverified Commit 22b13291 authored by Wolfgang Welz's avatar Wolfgang Welz Committed by GitHub
Browse files

Fix: Report HTTP server errors (#370)

parent aba33d58
No related branches found
No related tags found
No related merge requests found
...@@ -20,16 +20,18 @@ var ( ...@@ -20,16 +20,18 @@ var (
engine *echo.Echo engine *echo.Echo
) )
const name = "Analysis HTTP Server" // PluginName is the name of the analysis server plugin.
const PluginName = "Analysis HTTP Server"
var assetsBox = packr.New("Assets", "./static") var assetsBox = packr.New("Assets", "./static")
// Configure configures the plugin. // Configure configures the plugin.
func Configure() { func Configure() {
log = logger.NewLogger(name) log = logger.NewLogger(PluginName)
engine = echo.New() engine = echo.New()
engine.HideBanner = true engine.HideBanner = true
engine.HidePort = true
// we only need this special flag, because we always keep a packed box in the same directory // we only need this special flag, because we always keep a packed box in the same directory
if config.Node.GetBool(CfgDev) { if config.Node.GetBool(CfgDev) {
...@@ -47,17 +49,19 @@ func Configure() { ...@@ -47,17 +49,19 @@ func Configure() {
// Run runs the plugin. // Run runs the plugin.
func Run() { func Run() {
log.Infof("Starting %s ...", name) log.Infof("Starting %s ...", PluginName)
if err := daemon.BackgroundWorker(name, start, shutdown.PriorityAnalysis); err != nil { if err := daemon.BackgroundWorker(PluginName, worker, shutdown.PriorityAnalysis); err != nil {
log.Errorf("Error starting as daemon: %s", err) log.Errorf("Error starting as daemon: %s", err)
} }
} }
func start(shutdownSignal <-chan struct{}) { func worker(shutdownSignal <-chan struct{}) {
defer log.Infof("Stopping %s ... done", PluginName)
stopped := make(chan struct{}) stopped := make(chan struct{})
bindAddr := config.Node.GetString(CfgBindAddress) bindAddr := config.Node.GetString(CfgBindAddress)
go func() { go func() {
log.Infof("Started %s: http://%s", name, bindAddr) log.Infof("Started %s: http://%s", PluginName, bindAddr)
if err := engine.Start(bindAddr); err != nil { if err := engine.Start(bindAddr); err != nil {
if !errors.Is(err, http.ErrServerClosed) { if !errors.Is(err, http.ErrServerClosed) {
log.Errorf("Error serving: %s", err) log.Errorf("Error serving: %s", err)
...@@ -66,19 +70,18 @@ func start(shutdownSignal <-chan struct{}) { ...@@ -66,19 +70,18 @@ func start(shutdownSignal <-chan struct{}) {
} }
}() }()
// stop if we are shutting down or the server could not be started
select { select {
case <-shutdownSignal: case <-shutdownSignal:
case <-stopped: case <-stopped:
} }
log.Infof("Stopping %s ...", name) log.Infof("Stopping %s ...", PluginName)
ctx, cancel := context.WithTimeout(context.Background(), time.Second) ctx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel() defer cancel()
if err := engine.Shutdown(ctx); err != nil { if err := engine.Shutdown(ctx); err != nil {
log.Errorf("Error stopping: %s", err) log.Errorf("Error stopping: %s", err)
} }
log.Info("Stopping %s ... done", name)
} }
func index(e echo.Context) error { func index(e echo.Context) error {
......
package dashboard package dashboard
import ( import (
"context"
"errors"
"net" "net"
"net/http" "net/http"
"runtime" "runtime"
...@@ -34,7 +36,9 @@ const PluginName = "Dashboard" ...@@ -34,7 +36,9 @@ const PluginName = "Dashboard"
var ( var (
// Plugin is the plugin instance of the dashboard plugin. // Plugin is the plugin instance of the dashboard plugin.
Plugin = node.NewPlugin(PluginName, node.Enabled, configure, run) Plugin = node.NewPlugin(PluginName, node.Enabled, configure, run)
log *logger.Logger log *logger.Logger
server *echo.Echo
nodeStartAt = time.Now() nodeStartAt = time.Now()
...@@ -60,54 +64,79 @@ func configure(plugin *node.Plugin) { ...@@ -60,54 +64,79 @@ func configure(plugin *node.Plugin) {
configureLiveFeed() configureLiveFeed()
configureDrngLiveFeed() configureDrngLiveFeed()
configureServer()
} }
func run(plugin *node.Plugin) { func configureServer() {
notifyStatus := events.NewClosure(func(mps uint64) { server = echo.New()
wsSendWorkerPool.TrySubmit(mps) server.HideBanner = true
}) server.HidePort = true
server.Use(middleware.Recover())
daemon.BackgroundWorker("Dashboard[WSSend]", func(shutdownSignal <-chan struct{}) {
metrics.Events.ReceivedMPSUpdated.Attach(notifyStatus)
wsSendWorkerPool.Start()
<-shutdownSignal
log.Info("Stopping Dashboard[WSSend] ...")
metrics.Events.ReceivedMPSUpdated.Detach(notifyStatus)
wsSendWorkerPool.Stop()
log.Info("Stopping Dashboard[WSSend] ... done")
}, shutdown.PriorityDashboard)
runLiveFeed() if config.Node.GetBool(CfgBasicAuthEnabled) {
server.Use(middleware.BasicAuth(func(username, password string, c echo.Context) (bool, error) {
if username == config.Node.GetString(CfgBasicAuthUsername) &&
password == config.Node.GetString(CfgBasicAuthPassword) {
return true, nil
}
return false, nil
}))
}
setupRoutes(server)
}
func run(*node.Plugin) {
// rune the message live feed
runLiveFeed()
// run dRNG live feed if dRNG plugin is enabled // run dRNG live feed if dRNG plugin is enabled
if !node.IsSkipped(drng.Plugin) { if !node.IsSkipped(drng.Plugin) {
runDrngLiveFeed() runDrngLiveFeed()
} }
// allow any origin for websocket connections log.Infof("Starting %s ...", PluginName)
upgrader.CheckOrigin = func(r *http.Request) bool { if err := daemon.BackgroundWorker(PluginName, worker, shutdown.PriorityAnalysis); err != nil {
return true log.Errorf("Error starting as daemon: %s", err)
} }
}
e := echo.New() func worker(shutdownSignal <-chan struct{}) {
e.HideBanner = true defer log.Infof("Stopping %s ... done", PluginName)
e.Use(middleware.Recover())
// start the web socket worker pool
if config.Node.GetBool(CfgBasicAuthEnabled) { wsSendWorkerPool.Start()
e.Use(middleware.BasicAuth(func(username, password string, c echo.Context) (bool, error) { defer wsSendWorkerPool.Stop()
if username == config.Node.GetString(CfgBasicAuthUsername) &&
password == config.Node.GetString(CfgBasicAuthPassword) { // submit the mps to the worker pool when triggered
return true, nil notifyStatus := events.NewClosure(func(mps uint64) { wsSendWorkerPool.TrySubmit(mps) })
metrics.Events.ReceivedMPSUpdated.Attach(notifyStatus)
defer metrics.Events.ReceivedMPSUpdated.Detach(notifyStatus)
stopped := make(chan struct{})
bindAddr := config.Node.GetString(CfgBindAddress)
go func() {
log.Infof("Started %s: http://%s", PluginName, bindAddr)
if err := server.Start(bindAddr); err != nil {
if !errors.Is(err, http.ErrServerClosed) {
log.Errorf("Error serving: %s", err)
} }
return false, nil close(stopped)
})) }
} }()
setupRoutes(e) // stop if we are shutting down or the server could not be started
addr := config.Node.GetString(CfgBindAddress) select {
case <-shutdownSignal:
case <-stopped:
}
log.Infof("You can now access the dashboard using: http://%s", addr) log.Infof("Stopping %s ...", PluginName)
go e.Start(addr) ctx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel()
if err := server.Shutdown(ctx); err != nil {
log.Errorf("Error stopping: %s", err)
}
} }
// sends the given message to all connected websocket clients // sends the given message to all connected websocket clients
...@@ -128,6 +157,7 @@ var webSocketWriteTimeout = time.Duration(3) * time.Second ...@@ -128,6 +157,7 @@ var webSocketWriteTimeout = time.Duration(3) * time.Second
var ( var (
upgrader = websocket.Upgrader{ upgrader = websocket.Upgrader{
HandshakeTimeout: webSocketWriteTimeout, HandshakeTimeout: webSocketWriteTimeout,
CheckOrigin: func(r *http.Request) bool { return true },
EnableCompression: true, EnableCompression: true,
} }
) )
...@@ -195,7 +225,7 @@ type neighbormetric struct { ...@@ -195,7 +225,7 @@ type neighbormetric struct {
} }
func neighborMetrics() []neighbormetric { func neighborMetrics() []neighbormetric {
stats := []neighbormetric{} var stats []neighbormetric
// gossip plugin might be disabled // gossip plugin might be disabled
neighbors := gossip.Manager().AllNeighbors() neighbors := gossip.Manager().AllNeighbors()
......
...@@ -2,6 +2,8 @@ package webapi ...@@ -2,6 +2,8 @@ package webapi
import ( import (
"context" "context"
"errors"
"net/http"
"time" "time"
"github.com/iotaledger/goshimmer/packages/shutdown" "github.com/iotaledger/goshimmer/packages/shutdown"
...@@ -18,38 +20,52 @@ const PluginName = "WebAPI" ...@@ -18,38 +20,52 @@ const PluginName = "WebAPI"
var ( var (
// Plugin is the plugin instance of the web API plugin. // Plugin is the plugin instance of the web API plugin.
Plugin = node.NewPlugin(PluginName, node.Enabled, configure, run) Plugin = node.NewPlugin(PluginName, node.Enabled, configure, run)
log *logger.Logger
// Server is the web API server. // Server is the web API server.
Server = echo.New() Server = echo.New()
log *logger.Logger
) )
func configure(plugin *node.Plugin) { func configure(*node.Plugin) {
log = logger.NewLogger(PluginName) log = logger.NewLogger(PluginName)
// configure the server
Server.HideBanner = true Server.HideBanner = true
Server.HidePort = true Server.HidePort = true
Server.GET("/", IndexRequest) Server.GET("/", IndexRequest)
} }
func run(plugin *node.Plugin) { func run(*node.Plugin) {
log.Info("Starting Web Server ...") log.Infof("Starting %s ...", PluginName)
if err := daemon.BackgroundWorker("WebAPI Server", worker, shutdown.PriorityWebAPI); err != nil {
log.Errorf("Error starting as daemon: %s", err)
}
}
daemon.BackgroundWorker("WebAPI Server", func(shutdownSignal <-chan struct{}) { func worker(shutdownSignal <-chan struct{}) {
log.Info("Starting Web Server ... done") defer log.Infof("Stopping %s ... done", PluginName)
go func() { stopped := make(chan struct{})
if err := Server.Start(config.Node.GetString(CfgBindAddress)); err != nil { bindAddr := config.Node.GetString(CfgBindAddress)
log.Info("Stopping Web Server ... done") go func() {
log.Infof("Started %s: http://%s", PluginName, bindAddr)
if err := Server.Start(bindAddr); err != nil {
if !errors.Is(err, http.ErrServerClosed) {
log.Errorf("Error serving: %s", err)
} }
}() close(stopped)
}
<-shutdownSignal }()
log.Info("Stopping Web Server ...") // stop if we are shutting down or the server could not be started
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second) select {
defer cancel() case <-shutdownSignal:
case <-stopped:
}
if err := Server.Shutdown(ctx); err != nil { log.Infof("Stopping %s ...", PluginName)
log.Errorf("Couldn't stop server cleanly: %s", err.Error()) ctx, cancel := context.WithTimeout(context.Background(), time.Second)
} defer cancel()
}, shutdown.PriorityWebAPI) if err := Server.Shutdown(ctx); err != nil {
log.Errorf("Error stopping: %s", err)
}
} }
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment