forked from megamsys/vertice
/
service.go
115 lines (106 loc) · 2.78 KB
/
service.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
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
package httpd
import (
"fmt"
"net"
"net/http"
"strings"
"sync"
"time"
log "github.com/Sirupsen/logrus"
"github.com/codegangsta/negroni"
"github.com/megamsys/vertice/api"
"github.com/megamsys/vertice/subd/httpd/shutdown"
"gopkg.in/tylerb/graceful.v1"
)
// Service manages the listener and handler for an HTTP endpoint.
type Service struct {
ln *graceful.Server
addr string
tls bool
certFile string
keyFile string
err chan error
shutdownChan chan bool
hlr *negroni.Negroni
}
// NewService returns a new instance of Service.
func NewService(c *Config) *Service {
s := &Service{
addr: c.BindAddress,
tls: c.UseTls,
certFile: c.CertFile,
keyFile: c.KeyFile,
err: make(chan error),
hlr: api.NewNegHandler(),
}
return s
}
// Open starts the service
func (s *Service) Open() error {
log.Infof("starting httpd service")
shutdownChan := make(chan bool)
shutdownTimeout := 10 * 60
idleTracker := newIdleTracker()
shutdown.Register(idleTracker)
shutdown.Register(&api.LogTracker)
readTimeout := 10 * 60
writeTimeout := 10 * 60
srv := &graceful.Server{
Timeout: time.Duration(shutdownTimeout) * time.Second,
Server: &http.Server{
ReadTimeout: time.Duration(readTimeout) * time.Second,
WriteTimeout: time.Duration(writeTimeout) * time.Second,
Addr: s.addr,
Handler: s.hlr,
},
ConnState: func(conn net.Conn, state http.ConnState) {
idleTracker.trackConn(conn, state)
},
ShutdownInitiated: func() {
log.Debugf("httpd is shutting down, waiting for pending connections to finish.")
handlers := shutdown.All()
wg := sync.WaitGroup{}
for _, h := range handlers {
wg.Add(1)
go func(h shutdown.Shutdownable) {
defer wg.Done()
log.Printf("httpd running shutdown handler %v\n", h)
h.Shutdown()
log.Printf("httpd running shutdown handler %v done\n", h)
}(h)
}
wg.Wait()
close(shutdownChan)
},
}
s.ln = srv
s.shutdownChan = shutdownChan
go s.serve()
return nil
}
// Close closes the underlying listener.
func (s *Service) Close() error {
gsrv := s.ln
if s.ln != nil {
//this is not graceful stop. and swallows the exception.
gsrv.Stop(time.Duration(1*60) * time.Second)
}
return nil
}
// Err returns a channel for fatal errors that occur on the listener.
func (s *Service) Err() <-chan error { return s.err }
// serve serves the handler from the listener.
func (s *Service) serve() {
var err error
if s.tls {
log.Printf(" > httpd https://%s", s.addr)
err = s.ln.ListenAndServeTLS(s.certFile, s.keyFile)
} else {
log.Printf(" > httpd http://%s", s.addr)
err = s.ln.ListenAndServe()
}
if err != nil && !strings.Contains(err.Error(), "closed") {
s.err <- fmt.Errorf("httpd http://%s\n%s", s.addr, err)
}
<-s.shutdownChan
}