-
Notifications
You must be signed in to change notification settings - Fork 0
/
runner.go
108 lines (89 loc) · 1.81 KB
/
runner.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
package lameduck
import (
"context"
"errors"
"net/http"
"os"
"sync"
"time"
"golang.org/x/sys/unix"
"toolman.org/base/log/v2"
)
var (
defaultPeriod = 3 * time.Second
defaultSignals = []os.Signal{unix.SIGINT, unix.SIGTERM}
)
// Runner is the lame-duck coordinator for a type implementing the Server
// interface.
type Runner struct {
server Server
period time.Duration
escOK bool
signals []os.Signal
logf func(string, ...interface{})
psHook hookFunction
state State
ready chan struct{}
done chan struct{}
once sync.Once
}
func newRunner(svr Server, options []Option) (*Runner, error) {
if svr == nil {
return nil, errors.New("nil Server")
}
r := &Runner{
server: svr,
period: defaultPeriod,
signals: defaultSignals,
logf: log.Infof,
state: NotStarted,
ready: make(chan struct{}),
done: make(chan struct{}),
}
for _, o := range options {
o.set(r)
}
if r.period <= 0 {
return nil, errors.New("lame-duck period must be greater than zero")
}
if len(r.signals) == 0 {
return nil, errors.New("no lame-duck signals defined")
}
return r, nil
}
func (r *Runner) serve(ctx context.Context) error {
if r == nil {
return errors.New("bad state: nil receiver")
}
err := r.server.Serve(ctx)
switch {
case err == nil:
return nil
case r.escOK && err == http.ErrServerClosed:
return nil
default:
return err
}
}
// Ready returns a channel that is closed when the receiver's underlying
// Server is ready to serve reqeuests.
func (r *Runner) Ready() <-chan struct{} {
return r.ready
}
func (r *Runner) close() {
if r == nil || r.done == nil {
if r != nil {
r.logf("r.done is nil !!!")
}
return
}
var closed bool
r.once.Do(func() {
close(r.done)
r.logf("runner closed")
closed = true
})
if !closed {
r.logf("runner *NOT* closed")
}
}