-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmain.go
More file actions
142 lines (122 loc) · 3.25 KB
/
main.go
File metadata and controls
142 lines (122 loc) · 3.25 KB
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
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
package main
import (
"context"
"fmt"
"net/http"
"syscall"
"time"
"github.com/jimmicro/grace"
)
// HTTPServer example HTTP server
type HTTPServer struct {
server *http.Server
}
func NewHTTPServer(addr string) *HTTPServer {
mux := http.NewServeMux()
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
time.Sleep(10 * time.Second) // sleep 10 seconds,mock long time processing
_, _ = w.Write([]byte("Hello, World!"))
})
mux.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
_, _ = w.Write([]byte("OK"))
})
return &HTTPServer{
server: &http.Server{
Addr: addr,
Handler: mux,
},
}
}
func (h *HTTPServer) Run(ctx context.Context) error {
// start server in a separate goroutine
errCh := make(chan error, 1)
go func() {
if err := h.server.ListenAndServe(); err != nil && err != http.ErrServerClosed {
errCh <- err
}
}()
// wait for context done or server error
select {
case <-ctx.Done():
return nil
case err := <-errCh:
return err
}
}
func (h *HTTPServer) Shutdown(ctx context.Context) error {
return h.server.Shutdown(ctx)
}
func (h *HTTPServer) Name() string {
return fmt.Sprintf("HTTP Server (%s)", h.server.Addr)
}
// BackgroundWorker example background worker service
type BackgroundWorker struct {
name string
interval time.Duration
stopCh chan struct{}
}
func NewBackgroundWorker(name string, interval time.Duration) *BackgroundWorker {
return &BackgroundWorker{
name: name,
interval: interval,
stopCh: make(chan struct{}),
}
}
func (w *BackgroundWorker) Run(ctx context.Context) error {
ticker := time.NewTicker(w.interval)
defer ticker.Stop()
usedTime := time.Now()
for {
select {
case <-ctx.Done():
return nil
case t := <-ticker.C:
fmt.Printf("[%s] execute background task...\n", w.name)
// if used time is greater than 10 seconds, return error
if t.Sub(usedTime) > 10*time.Second {
return fmt.Errorf("used time is greater than 10 seconds")
}
case <-w.stopCh:
return nil
}
}
}
func (w *BackgroundWorker) Shutdown(ctx context.Context) error {
close(w.stopCh)
fmt.Printf("[%s] background worker stopped\n", w.name)
return nil
}
func (w *BackgroundWorker) Name() string {
return w.name
}
func main() {
// create service instance
httpServer := NewHTTPServer(":8080")
worker1 := NewBackgroundWorker("data processor", 5*time.Second)
worker2 := NewBackgroundWorker("log cleaner", 10*time.Second)
// create service list
services := []grace.Grace{
httpServer,
worker1,
worker2,
}
// create shepherd
shepherd := grace.NewShepherd(services,
grace.WithTimeout(15*time.Second), // 15 seconds timeout
grace.WithLogger(&customLogger{}), // use custom logger
grace.WithSignals(syscall.SIGINT,
syscall.SIGTERM,
syscall.SIGQUIT),
)
shepherd.Start(context.Background())
}
// customLogger example custom logger
type customLogger struct{}
func (l *customLogger) Info(msg string, args ...interface{}) {
fmt.Printf("[INFO] %s "+msg+"\n", append([]interface{}{time.Now().Format("15:04:05")}, args...)...)
}
func (l *customLogger) Error(msg string, args ...interface{}) {
fmt.Printf("[ERROR] %s "+msg+"\n", append([]interface{}{time.Now().Format("15:04:05")}, args...)...)
}