/
server_group.go
95 lines (80 loc) · 2.73 KB
/
server_group.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
/****************************************************************************
* Copyright 2019, Optimizely, Inc. and contributors *
* *
* Licensed under the Apache License, Version 2.0 (the "License"); *
* you may not use this file except in compliance with the License. *
* You may obtain a copy of the License at *
* *
* http://www.apache.org/licenses/LICENSE-2.0 *
* *
* Unless required by applicable law or agreed to in writing, software *
* distributed under the License is distributed on an "AS IS" BASIS, *
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
* See the License for the specific language governing permissions and *
* limitations under the License. *
***************************************************************************/
// Package server provides a basic HTTP server wrapper
package server
import (
"context"
"fmt"
"net/http"
"sync"
"github.com/optimizely/agent/config"
"github.com/rs/zerolog/log"
"golang.org/x/sync/errgroup"
)
// Group encapsulates managing multiple Server instances
type Group struct {
stop context.CancelFunc
eg *errgroup.Group
ctx context.Context
conf config.ServerConfig
}
// NewGroup creares a new server group.
func NewGroup(ctx context.Context, conf config.ServerConfig) *Group {
nctx, stop := context.WithCancel(ctx)
eg, gctx := errgroup.WithContext(nctx)
return &Group{
stop: stop,
eg: eg,
ctx: gctx,
conf: conf,
}
}
// GoListenAndServe constructs a NewServer and adds it to the Group.
// Two goroutines are started. One for the http listener and one
// to initiate a graceful shutdown. This method blocks on adding the
// go routines to maintain startup order of each listener.
func (g *Group) GoListenAndServe(name, port string, handler http.Handler) {
if port == "0" {
log.Info().Msg(fmt.Sprintf(`"%s" not enabled`, name))
return
}
server, err := NewServer(name, port, handler, g.conf)
if err != nil {
log.Error().Err(err).Msg("Failed starting server")
g.stop()
return
}
wg := sync.WaitGroup{}
wg.Add(1)
g.eg.Go(func() error {
wg.Done()
defer g.stop()
return server.ListenAndServe()
})
// Shutdown on signal
wg.Add(1)
g.eg.Go(func() error {
wg.Done()
<-g.ctx.Done()
server.Shutdown()
return g.ctx.Err()
})
wg.Wait()
}
// Wait waits for all servers to complete before returning
func (g *Group) Wait() error {
return g.eg.Wait()
}