Skip to content

Commit c238ce9

Browse files
committed
add comment to clarify the etcd shutting down workflow
Signed-off-by: Benjamin Wang <[email protected]>
1 parent 0dcb17d commit c238ce9

File tree

1 file changed

+35
-3
lines changed

1 file changed

+35
-3
lines changed

server/embed/etcd.go

+35-3
Original file line numberDiff line numberDiff line change
@@ -388,6 +388,24 @@ func (e *Etcd) Config() Config {
388388
// Close gracefully shuts down all servers/listeners.
389389
// Client requests will be terminated with request timeout.
390390
// After timeout, enforce remaning requests be closed immediately.
391+
//
392+
// The rough workflow to shut down etcd:
393+
// 1. close the `stopc` channel, so that all error handlers (child
394+
// goroutines) won't send back any errors anymore;
395+
// 2. close all client and metrics listeners, so that etcd server
396+
// stops receiving any new connection immediately;
397+
// 3. stop the http and grpc servers gracefully, within request timeout;
398+
// 4. call the cancel function to close the gateway context, so that
399+
// all gateway connections are closed.
400+
// 5. stop etcd server gracefully, and ensure the main raft loop
401+
// goroutine is stopped;
402+
// 6. stop all peer listeners, so that it stops receives peer connections
403+
// and messages (wait up to 1-second);
404+
// 7. wait for all child goroutines (i.e. client handlers, peer handlers
405+
// and metrics handlers) to exit;
406+
// 8. close the `errc` channel to release the resource. Note that it's only
407+
// safe to close the `errc` after step 6 above is done, otherwise the
408+
// child goroutines may send errors back to already closed `errc` channel.
391409
func (e *Etcd) Close() {
392410
fields := []zap.Field{
393411
zap.String("name", e.cfg.Name),
@@ -407,10 +425,14 @@ func (e *Etcd) Close() {
407425
lg.Sync()
408426
}()
409427

428+
// 1. close the `stopc` channel, so that all error handlers (child
429+
// goroutines) won't send back any errors anymore;
410430
e.closeOnce.Do(func() {
411431
close(e.stopc)
412432
})
413433

434+
// 2. close all client and metrics listeners, so that etcd server
435+
// stops receiving any new connection immediately;
414436
for i := range e.Clients {
415437
if e.Clients[i] != nil {
416438
e.Clients[i].Close()
@@ -421,7 +443,7 @@ func (e *Etcd) Close() {
421443
e.metricsListeners[i].Close()
422444
}
423445

424-
// close client requests with request timeout
446+
// 3. stop the http and grpc servers gracefully, within request timeout;
425447
timeout := 2 * time.Second
426448
if e.Server != nil {
427449
timeout = e.Server.Cfg.ReqTimeout()
@@ -434,6 +456,8 @@ func (e *Etcd) Close() {
434456
}
435457
}
436458

459+
// 4. call the cancel function to close the gateway context, so that
460+
// all gateway connections are closed.
437461
for _, sctx := range e.sctxs {
438462
sctx.cancel()
439463
}
@@ -443,12 +467,14 @@ func (e *Etcd) Close() {
443467
e.tracingExporterShutdown()
444468
}
445469

446-
// close rafthttp transports
470+
// 5. stop etcd server gracefully, and ensure the main raft loop
471+
// goroutine is stopped;
447472
if e.Server != nil {
448473
e.Server.Stop()
449474
}
450475

451-
// close all idle connections in peer handler (wait up to 1-second)
476+
// 6. stop all peer listeners, so that it stops receives peer connections
477+
// and messages (wait up to 1-second);
452478
for i := range e.Peers {
453479
if e.Peers[i] != nil && e.Peers[i].close != nil {
454480
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
@@ -457,7 +483,13 @@ func (e *Etcd) Close() {
457483
}
458484
}
459485
if e.errc != nil {
486+
// 7. wait for all child goroutines (i.e. client handlers, peer handlers
487+
// and metrics handlers) to exit;
460488
e.wg.Wait()
489+
490+
// 8. close the `errc` channel to release the resource. Note that it's only
491+
// safe to close the `errc` after step 6 above is done, otherwise the
492+
// child goroutines may send errors back to already closed `errc` channel.
461493
close(e.errc)
462494
}
463495
}

0 commit comments

Comments
 (0)