Skip to content

Commit 201568a

Browse files
committed
add commment to clarify the etcd shutting down workflow
Signed-off-by: Benjamin Wang <[email protected]>
1 parent 86a3170 commit 201568a

File tree

2 files changed

+43
-6
lines changed

2 files changed

+43
-6
lines changed

server/embed/etcd.go

+33-4
Original file line numberDiff line numberDiff line change
@@ -79,12 +79,23 @@ type Etcd struct {
7979

8080
Server *etcdserver.EtcdServer
8181

82-
cfg Config
83-
stopc chan struct{}
84-
errc chan error
82+
cfg Config
8583

84+
// closeOnce is to ensure `stopc` is closed only once, no matter
85+
// how many times the Close() method is called.
8686
closeOnce sync.Once
87-
wg sync.WaitGroup
87+
// stopc is used to notify the sub goroutines not to send
88+
// any errors to `errc`.
89+
stopc chan struct{}
90+
// errc is used to receive error from sub goroutines (including
91+
// client handler, peer handler and metrics handler). It's closed
92+
// after all these sub goroutines exit (checked via `wg`). Writers
93+
// should avoid writing after `stopc` is closed by selecting on
94+
// reading from `stopc`.
95+
errc chan error
96+
97+
// wg is used to track the lifecycle of all sub goroutines created by `StartEtcd`.
98+
wg sync.WaitGroup
8899
}
89100

90101
type peerListener struct {
@@ -388,6 +399,24 @@ func (e *Etcd) Config() Config {
388399
// Close gracefully shuts down all servers/listeners.
389400
// Client requests will be terminated with request timeout.
390401
// After timeout, enforce remaning requests be closed immediately.
402+
//
403+
// The rough workflow to shut down etcd:
404+
// 1. close the `stopc` channel, so that all error handlers (child
405+
// goroutines) won't send back any errors anymore;
406+
// 2. stop the http and grpc servers gracefully, within request timeout;
407+
// 3. close all client and metrics listeners, so that etcd server
408+
// stops receiving any new connection;
409+
// 4. call the cancel function to close the gateway context, so that
410+
// all gateway connections are closed.
411+
// 5. stop etcd server gracefully, and ensure the main raft loop
412+
// goroutine is stopped;
413+
// 6. stop all peer listeners, so that it stops receiving peer connections
414+
// and messages (wait up to 1-second);
415+
// 7. wait for all child goroutines (i.e. client handlers, peer handlers
416+
// and metrics handlers) to exit;
417+
// 8. close the `errc` channel to release the resource. Note that it's only
418+
// safe to close the `errc` after step 7 above is done, otherwise the
419+
// child goroutines may send errors back to already closed `errc` channel.
391420
func (e *Etcd) Close() {
392421
fields := []zap.Field{
393422
zap.String("name", e.cfg.Name),

server/embed/serve.go

+10-2
Original file line numberDiff line numberDiff line change
@@ -61,14 +61,22 @@ type serveCtx struct {
6161
insecure bool
6262
httpOnly bool
6363

64+
// ctx is used to control the grpc gateway. Terminate the grpc gateway
65+
// by calling `cancel` when shutting down the etcd.
6466
ctx context.Context
6567
cancel context.CancelFunc
6668

6769
userHandlers map[string]http.Handler
6870
serviceRegister func(*grpc.Server)
69-
serversC chan *servers
70-
closeOnce sync.Once
7171

72+
// serversC is used to receive the http and grpc server objects (created
73+
// in `serve`), both of which will be closed when shutting down the etcd.
74+
// Close it when `serve` returns or when etcd fails to bootstrap.
75+
serversC chan *servers
76+
// closeOnce is to ensure `serversC` is closed only once.
77+
closeOnce sync.Once
78+
79+
// wg is used to track the lifecycle of all sub goroutines created by `serve`.
7280
wg sync.WaitGroup
7381
}
7482

0 commit comments

Comments
 (0)