fix: Fixes to server shutdown stream
This commit is contained in:
+40
-9
@@ -2,9 +2,13 @@ package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/signal"
|
||||
"strings"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"gitea.hostxtra.co.uk/mrhid6/vantage/server/internal/api"
|
||||
@@ -141,13 +145,15 @@ func serve() {
|
||||
}
|
||||
log.Printf("message bus ready as node %s", bus.NodeID())
|
||||
|
||||
ctx := context.Background()
|
||||
// Cancelled on SIGTERM/SIGINT. Everything below that takes a context — the
|
||||
// housekeeping jobs, the leader lock — stops when the pod is asked to.
|
||||
ctx, shutdown := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
|
||||
defer shutdown()
|
||||
|
||||
go func() {
|
||||
if err := grpcserver.StartGRPC(9090); err != nil {
|
||||
log.Fatalf("gRPC server error: %v", err)
|
||||
}
|
||||
}()
|
||||
stopGRPC, err := grpcserver.StartGRPC(9090)
|
||||
if err != nil {
|
||||
log.Fatalf("gRPC server error: %v", err)
|
||||
}
|
||||
|
||||
// Everything below runs on exactly one replica at a time.
|
||||
//
|
||||
@@ -183,12 +189,37 @@ func serve() {
|
||||
r.Use(corsMiddleware())
|
||||
api.RegisterRoutes(r)
|
||||
|
||||
log.Println("REST server listening on :8080")
|
||||
if err := r.Run(":8080"); err != nil {
|
||||
log.Fatalf("REST server error: %v", err)
|
||||
srv := &http.Server{Addr: ":8080", Handler: r}
|
||||
go func() {
|
||||
log.Println("REST server listening on :8080")
|
||||
if err := srv.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) {
|
||||
log.Fatalf("REST server error: %v", err)
|
||||
}
|
||||
}()
|
||||
|
||||
<-ctx.Done()
|
||||
log.Println("shutdown signal received")
|
||||
|
||||
// gRPC first, and this ordering is the point of the whole exercise. Stopping
|
||||
// it runs each CommandStream handler's deferred release, which clears that
|
||||
// agent's presence claim; until that happens another replica will keep
|
||||
// dispatching commands to this process. Draining HTTP first would leave the
|
||||
// claims held for the length of the drain.
|
||||
stopGRPC()
|
||||
|
||||
drainCtx, cancelDrain := context.WithTimeout(context.Background(), httpDrainTimeout)
|
||||
defer cancelDrain()
|
||||
if err := srv.Shutdown(drainCtx); err != nil {
|
||||
log.Printf("REST server shutdown: %v", err)
|
||||
}
|
||||
log.Println("shutdown complete")
|
||||
}
|
||||
|
||||
// How long in-flight REST requests are given to finish. Console tunnels are
|
||||
// long-lived WebSockets that will not end on their own, so this is a ceiling
|
||||
// rather than a target; the relays behind them are already gone by this point.
|
||||
const httpDrainTimeout = 10 * time.Second
|
||||
|
||||
func corsMiddleware() gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
c.Header("Access-Control-Allow-Origin", "*")
|
||||
|
||||
Reference in New Issue
Block a user