@@ -3,10 +3,12 @@ package toxiproxy
3
3
import (
4
4
"context"
5
5
"encoding/json"
6
+ "errors"
6
7
"fmt"
7
8
"net/http"
8
9
"os"
9
10
"strings"
11
+ "sync"
10
12
"time"
11
13
12
14
"github.com/gorilla/mux"
@@ -34,7 +36,9 @@ type ApiServer struct {
34
36
Collection * ProxyCollection
35
37
Metrics * metricsContainer
36
38
Logger * zerolog.Logger
37
- http * http.Server
39
+
40
+ initOnce sync.Once // guards shutdown
41
+ shutdown func (ctx context.Context ) error
38
42
}
39
43
40
44
const (
@@ -50,42 +54,45 @@ func NewServer(m *metricsContainer, logger zerolog.Logger) *ApiServer {
50
54
}
51
55
}
52
56
53
- func (server * ApiServer ) Listen (addr string ) error {
54
- server .Logger .
55
- Info ().
56
- Str ("address" , addr ).
57
- Msg ("Starting Toxiproxy HTTP server" )
57
+ var errServerStarted = errors .New ("server already started" )
58
58
59
- server .http = & http.Server {
60
- Addr : addr ,
61
- Handler : server .Routes (),
62
- WriteTimeout : wait_timeout ,
63
- ReadTimeout : read_timeout ,
64
- IdleTimeout : 60 * time .Second ,
59
+ func (server * ApiServer ) Listen (addr string ) error {
60
+ var s * http.Server
61
+ server .initOnce .Do (func () {
62
+ server .Logger .
63
+ Info ().
64
+ Str ("address" , addr ).
65
+ Msg ("Starting Toxiproxy HTTP server" )
66
+
67
+ s = & http.Server {
68
+ Addr : addr ,
69
+ Handler : server .Routes (),
70
+ WriteTimeout : wait_timeout ,
71
+ ReadTimeout : read_timeout ,
72
+ IdleTimeout : 60 * time .Second ,
73
+ }
74
+ })
75
+ if s == nil {
76
+ return errServerStarted
65
77
}
66
78
67
- err := server .http .ListenAndServe ()
68
- if err == http .ErrServerClosed {
69
- err = nil
79
+ server .shutdown = s .Shutdown
80
+ err := s .ListenAndServe ()
81
+ if errors .Is (err , http .ErrServerClosed ) {
82
+ return nil
70
83
}
71
-
72
84
return err
73
85
}
74
86
75
87
func (server * ApiServer ) Shutdown () error {
76
- if server .http == nil {
77
- return nil
88
+ server .initOnce .Do (func () {})
89
+ if server .shutdown == nil {
90
+ return nil // in desire state
78
91
}
79
92
80
93
ctx , cancel := context .WithTimeout (context .Background (), wait_timeout )
81
94
defer cancel ()
82
-
83
- err := server .http .Shutdown (ctx )
84
- if err != nil {
85
- return err
86
- }
87
-
88
- return nil
95
+ return server .shutdown (ctx )
89
96
}
90
97
91
98
func (server * ApiServer ) Routes () * mux.Router {
0 commit comments