1
Fork 0

Implement graceful server shutdown.

This gives the user a friendly message when the server shuts down.
This commit is contained in:
Juliusz Chroboczek 2020-09-12 12:42:48 +02:00
parent 7707775cca
commit e37e27036e
5 changed files with 41 additions and 7 deletions

View File

@ -12,3 +12,7 @@ type client interface {
pushConn(id string, conn upConnection, tracks []upTrack, label string) error pushConn(id string, conn upConnection, tracks []upTrack, label string) error
pushClient(id, username string, add bool) error pushClient(id, username string, add bool) error
} }
type kickable interface {
kick(message string) error
}

View File

@ -64,7 +64,7 @@ type connectionFailedAction struct {
type permissionsChangedAction struct{} type permissionsChangedAction struct{}
type kickAction struct{ type kickAction struct {
message string message string
} }
@ -288,6 +288,16 @@ func (g *group) Range(f func(c client) bool) {
} }
} }
func (g *group) shutdown(message string) {
g.Range(func(c client) bool {
cc, ok := c.(kickable)
if ok {
cc.kick(message)
}
return true
})
}
const maxChatHistory = 20 const maxChatHistory = 20
func (g *group) clearChatHistory() { func (g *group) clearChatHistory() {

3
sfu.go
View File

@ -87,6 +87,7 @@ func main() {
webserver() webserver()
terminate := make(chan os.Signal, 1) terminate := make(chan os.Signal, 1)
signal.Notify(terminate, syscall.SIGINT) signal.Notify(terminate, syscall.SIGINT, syscall.SIGTERM)
<-terminate <-terminate
shutdown()
} }

View File

@ -943,6 +943,10 @@ func setPermissions(g *group, id string, perm string) error {
return c.action(permissionsChangedAction{}) return c.action(permissionsChangedAction{})
} }
func (c *webClient) kick(message string) error {
return c.action(kickAction{message})
}
func kickClient(g *group, id string, message string) error { func kickClient(g *group, id string, message string) error {
g.mu.Lock() g.mu.Lock()
defer g.mu.Unlock() defer g.mu.Unlock()
@ -952,12 +956,12 @@ func kickClient(g *group, id string, message string) error {
return userError("no such user") return userError("no such user")
} }
c, ok := client.(*webClient) c, ok := client.(kickable)
if !ok { if !ok {
return userError("this is not a real user") return userError("this client is not kickable")
} }
return c.action(kickAction{message}) return c.kick(message)
} }
func handleClientMessage(c *webClient, m clientMessage) error { func handleClientMessage(c *webClient, m clientMessage) error {

View File

@ -2,6 +2,7 @@ package main
import ( import (
"bufio" "bufio"
"context"
"encoding/json" "encoding/json"
"errors" "errors"
"fmt" "fmt"
@ -19,6 +20,8 @@ import (
"github.com/gorilla/websocket" "github.com/gorilla/websocket"
) )
var server *http.Server
func webserver() { func webserver() {
http.Handle("/", mungeHandler{http.FileServer(http.Dir(staticRoot))}) http.Handle("/", mungeHandler{http.FileServer(http.Dir(staticRoot))})
http.HandleFunc("/group/", groupHandler) http.HandleFunc("/group/", groupHandler)
@ -39,17 +42,24 @@ func webserver() {
http.HandleFunc("/stats", statsHandler) http.HandleFunc("/stats", statsHandler)
go func() { go func() {
server := &http.Server{ server = &http.Server{
Addr: httpAddr, Addr: httpAddr,
ReadHeaderTimeout: 60 * time.Second, ReadHeaderTimeout: 60 * time.Second,
IdleTimeout: 120 * time.Second, IdleTimeout: 120 * time.Second,
} }
server.RegisterOnShutdown(func() {
groups.mu.Lock()
defer groups.mu.Unlock()
for _, g := range groups.groups {
go g.shutdown("server is shutting down")
}
})
var err error var err error
err = server.ListenAndServeTLS( err = server.ListenAndServeTLS(
filepath.Join(dataDir, "cert.pem"), filepath.Join(dataDir, "cert.pem"),
filepath.Join(dataDir, "key.pem"), filepath.Join(dataDir, "key.pem"),
) )
if err != nil { if err != nil && err != http.ErrServerClosed {
log.Printf("ListenAndServeTLS: %v", err) log.Printf("ListenAndServeTLS: %v", err)
} }
}() }()
@ -457,3 +467,8 @@ func serveGroupRecordings(w http.ResponseWriter, r *http.Request, f *os.File, gr
fmt.Fprintf(w, "</table>\n") fmt.Fprintf(w, "</table>\n")
fmt.Fprintf(w, "</body></html>\n") fmt.Fprintf(w, "</body></html>\n")
} }
func shutdown() {
ctx, _ := context.WithTimeout(context.Background(), 2*time.Second)
server.Shutdown(ctx)
}