Skip to content

Commit

Permalink
stop: clarify the defer behavior of Stop, introduce EmergencyStop
Browse files Browse the repository at this point in the history
Release note: None
  • Loading branch information
knz committed Nov 14, 2022
1 parent 0ad0ad5 commit 8183c5e
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 6 deletions.
4 changes: 4 additions & 0 deletions pkg/cli/democluster/demo_cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -802,6 +802,10 @@ func TestingForceRandomizeDemoPorts() func() {

func (c *transientCluster) Close(ctx context.Context) {
if c.stopper != nil {
if r := recover(); r != nil {
c.stopper.EmergencyStop(ctx)
panic(r)
}
c.stopper.Stop(ctx)
}
if c.demoDir != "" {
Expand Down
40 changes: 34 additions & 6 deletions pkg/util/stop/stopper.go
Original file line number Diff line number Diff line change
Expand Up @@ -550,12 +550,7 @@ func (s *Stopper) Stop(ctx context.Context) {
// avoids stalls and helps some tests in `./cli` finish cleanly (where
// panics happen on purpose).
if r := recover(); r != nil {
go s.Quiesce(ctx)
s.mu.Lock()
for _, c := range s.mu.closers {
go c.Close()
}
s.mu.Unlock()
s.EmergencyStop(ctx)
panic(r)
}

Expand All @@ -569,6 +564,39 @@ func (s *Stopper) Stop(ctx context.Context) {
}
}

// EmergencyStop should be called instead of Stop() when the Stop()
// call is intended to be called under `defer`, but it cannot be
// called _directly_ via `defer`, and the caller intends the call to
// handle panics through the return path. For example, when
//
// defer stopper.Stop(ctx)
//
// is not directly possible, such as when the Stop call is inside a
// closure like this:
//
// defer func() {
// ... stopper.Stop(ctx) ...
// }()
//
// The Stop call will not catch panics properly. In that case,
// use:
//
// defer func() {
// if r := recover(); r != nil {
// stopper.EmergencyStop(ctx)
// panic(r)
// }
// stopper.Stop(ctx)
// }()
func (s *Stopper) EmergencyStop(ctx context.Context) {
go s.Quiesce(ctx)
s.mu.Lock()
defer s.mu.Unlock()
for _, c := range s.mu.closers {
go c.Close()
}
}

// ShouldQuiesce returns a channel which will be closed when Stop() has been
// invoked and outstanding tasks should begin to quiesce.
func (s *Stopper) ShouldQuiesce() <-chan struct{} {
Expand Down

0 comments on commit 8183c5e

Please sign in to comment.