Skip to content

Commit 3807853

Browse files
committed
Initial module commit
1 parent 51d0582 commit 3807853

File tree

2 files changed

+145
-0
lines changed

2 files changed

+145
-0
lines changed

go.mod

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
module github.com/codechimp-io/graceful
2+
3+
go 1.12
4+
5+
require (
6+
github.com/cloudflare/tableflip v1.0.0
7+
github.com/codechimp-io/log v1.0.3
8+
github.com/oklog/run v1.0.0
9+
)

graceful.go

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
package graceful
2+
3+
import (
4+
"context"
5+
"net/http"
6+
"os"
7+
"os/signal"
8+
"syscall"
9+
"time"
10+
11+
"github.com/cloudflare/tableflip"
12+
"github.com/codechimp-io/log"
13+
"github.com/oklog/run"
14+
)
15+
16+
var ShutdownTimeout = 3 * time.Second
17+
18+
// Run graceful http server
19+
func Run(server *http.Server, pidfile string) {
20+
// configure graceful restart
21+
upg, err := tableflip.New(tableflip.Options{
22+
PIDFile: pidfile,
23+
})
24+
if err != nil {
25+
log.Errorf("Creating graceful upgrader failed: %v", err)
26+
}
27+
defer upg.Stop()
28+
29+
// Do an upgrade on SIGHUP
30+
go func() {
31+
sig := make(chan os.Signal, 1)
32+
signal.Notify(sig, syscall.SIGHUP)
33+
for range sig {
34+
log.Info("Received SIGHUP, restaring gracefully...")
35+
err := upg.Upgrade()
36+
if err != nil {
37+
log.Errorf("Upgrade failed: %v", err)
38+
}
39+
}
40+
}()
41+
42+
var group run.Group
43+
44+
// Set up http server
45+
{
46+
ln, err := upg.Fds.Listen("tcp", server.Addr)
47+
if err != nil {
48+
log.Fatalf("Error creating new listener: %s", err)
49+
}
50+
51+
group.Add(
52+
func() error {
53+
log.Infof("Listening on [%s] with pid [%d]", server.Addr, os.Getpid())
54+
55+
return server.Serve(ln)
56+
},
57+
func(e error) {
58+
if e != nil {
59+
log.Fatalf("Failed to start HTTP Server: %v", e)
60+
}
61+
62+
log.Info("Shutting HTTP Server down")
63+
64+
ctx := context.Background()
65+
if ShutdownTimeout > 0 {
66+
var cancel context.CancelFunc
67+
ctx, cancel = context.WithTimeout(ctx, ShutdownTimeout)
68+
defer cancel()
69+
}
70+
71+
err := server.Shutdown(ctx)
72+
if err != nil {
73+
log.Errorf("Error shutting down HTTP server: %s", err)
74+
}
75+
76+
_ = server.Close()
77+
},
78+
)
79+
}
80+
81+
// Setup signal handler
82+
{
83+
var (
84+
cancelInterrupt = make(chan struct{})
85+
ch = make(chan os.Signal, 2)
86+
)
87+
defer close(ch)
88+
89+
group.Add(
90+
func() error {
91+
signal.Notify(ch, syscall.SIGINT, syscall.SIGTERM)
92+
93+
select {
94+
case sig := <-ch:
95+
switch sig {
96+
case syscall.SIGINT:
97+
log.Info("Received SIGINT, exiting gracefully...")
98+
case syscall.SIGTERM:
99+
log.Info("Received SIGTERM, exiting gracefully...")
100+
}
101+
102+
case <-cancelInterrupt:
103+
}
104+
105+
return nil
106+
},
107+
func(e error) {
108+
close(cancelInterrupt)
109+
signal.Stop(ch)
110+
},
111+
)
112+
}
113+
114+
{
115+
group.Add(
116+
func() error {
117+
// Tell the parent we are ready
118+
_ = upg.Ready()
119+
120+
// Wait for children to be ready
121+
// (or application shutdown)
122+
<-upg.Exit()
123+
124+
return nil
125+
},
126+
func(e error) {
127+
upg.Stop()
128+
},
129+
)
130+
}
131+
132+
err = group.Run()
133+
if err != nil {
134+
log.Fatalf("Error starting service: %s", err)
135+
}
136+
}

0 commit comments

Comments
 (0)