gobeetle: use standard graceful shutdown mechanism
MODIFY
go/go.mod
go/go.mod
@@ -13,6 +13,5 @@ require (
golang.org/x/text v0.3.0
gopkg.in/gorilla/websocket.v1 v1.4.0
gopkg.in/redis.v5 v5.2.9
- gopkg.in/tylerb/graceful.v1 v1.2.15
gopkg.in/yaml.v2 v2.2.2
)

MODIFY
go/go.sum
go/go.sum
@@ -411,8 +411,6 @@ gopkg.in/redis.v5 v5.2.9 h1:MNZYOLPomQzZMfpN3ZtD1uyJ2IDonTTlxYiV/pEApiw=
gopkg.in/redis.v5 v5.2.9/go.mod h1:6gtv0/+A4iM08kdRfocWYB3bLX2tebpNtfKlFT6H4mY=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
-gopkg.in/tylerb/graceful.v1 v1.2.15 h1:1JmOyhKqAyX3BgTXMI84LwT6FOJ4tP2N9e2kwTCM0nQ=
-gopkg.in/tylerb/graceful.v1 v1.2.15/go.mod h1:yBhekWvR20ACXVObSSdD3u6S9DeSylanL2PAbAC/uJ8=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=

MODIFY
go/server.go
go/server.go
@@ -2,7 +2,9 @@ package main
import (
"os"
+ "os/signal"
"sync"
+ "syscall"
"time"
// "github.com/davecgh/go-spew/spew"
@@ -30,6 +32,13 @@ var (
gcStatsTemplate string
)
+func waitForInterrupt() {
+ done := make(chan os.Signal, 1)
+ signal.Notify(done, os.Interrupt, syscall.SIGINT, syscall.SIGTERM)
+ <-done
+ logInfo("received interrupt")
+}
+
// RunConfigurationServer implements the main server loop.
func RunConfigurationServer(o ServerOptions) error {
logInfo("server started with options: %+v\n", o)
@@ -65,7 +74,11 @@ func RunConfigurationServer(o ServerOptions) error {
}
gcStatsTemplate = html
- state.clientHandler(state.GetConfig().Port)
+ srv := state.setupClientHandler(state.GetConfig().Port)
+ go state.runClientHandler(srv)
+ waitForInterrupt()
+ state.shutdownClientHandler(srv, 3*time.Second)
+
logInfo("shutting down")
// wait for web socket readers and writers to finish
if waitForWaitGroupWithTimeout(&state.waitGroup, 3*time.Second) {

MODIFY
go/server_state.go
go/server_state.go
package main
import (
+ "context"
"encoding/json"
"errors"
"fmt"
@@ -17,7 +18,6 @@ import (
// "github.com/davecgh/go-spew/spew"
"github.com/xing/beetle/consul"
"gopkg.in/gorilla/websocket.v1"
- "gopkg.in/tylerb/graceful.v1"
)
// ServerOptions for our server.
@@ -503,12 +503,32 @@ func (s *ServerState) LoadState() {
logInfo("restored client last seen info from redis: %v", s.clientsLastSeen)
}
-func (s *ServerState) clientHandler(webSocketPort int) {
+func (s *ServerState) setupClientHandler(webSocketPort int) *http.Server {
mux := http.NewServeMux()
mux.HandleFunc("/", s.dispatchRequest)
logInfo("Starting web socket server on port %d", webSocketPort)
webSocketSpec := ":" + strconv.Itoa(webSocketPort)
- graceful.Run(webSocketSpec, 10*time.Second, mux)
+ return &http.Server{
+ Addr: webSocketSpec,
+ Handler: mux,
+ }
+}
+
+func (s *ServerState) runClientHandler(srv *http.Server) {
+ if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
+ logError("starting websocket server failed")
+ }
+}
+
+func (s *ServerState) shutdownClientHandler(srv *http.Server, timeout time.Duration) {
+ ctx, cancel := context.WithTimeout(context.Background(), timeout)
+ defer cancel()
+ err := srv.Shutdown(ctx)
+ if err != nil {
+ logError("web server shutdown failed: %+v", err)
+ } else {
+ logInfo("web server shutdown successful")
+ }
}
func (s *ServerState) serveNotifications(w http.ResponseWriter, r *http.Request) {

gobeetle: use standard graceful shutdown mechanism