Skip to content

Commit

Permalink
prevent panic when closing channels
Browse files Browse the repository at this point in the history
  • Loading branch information
djelusic committed Nov 9, 2021
1 parent c583947 commit 6c87c3e
Show file tree
Hide file tree
Showing 4 changed files with 23 additions and 51 deletions.
37 changes: 13 additions & 24 deletions aws/cloudformation.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"context"
"fmt"
"strings"
"sync"
"time"

"github.com/aws/aws-sdk-go-v2/aws"
Expand Down Expand Up @@ -158,7 +159,9 @@ type StackWaiter struct {
cloudFormation *CloudFormation
errc chan error
done chan struct{}
loopDone chan struct{}
events chan types.StackEvent
closer sync.Once
}

func newStackWaiter(stackName string, cf *CloudFormation) *StackWaiter {
Expand All @@ -167,6 +170,7 @@ func newStackWaiter(stackName string, cf *CloudFormation) *StackWaiter {
cloudFormation: cf,
errc: make(chan error),
done: make(chan struct{}),
loopDone: make(chan struct{}),
events: make(chan types.StackEvent),
}
go sw.pollEvents()
Expand All @@ -178,50 +182,35 @@ func (w *StackWaiter) Wait() error {
}

func (w *StackWaiter) close(err error) {
if w.isDone() {
return
}
close(w.done)
close(w.events)
w.errc <- err
w.closer.Do(func() {
close(w.done)
<-w.loopDone
w.errc <- err
})
}

func (w *StackWaiter) Events() <-chan types.StackEvent {
return w.events
}

func (w *StackWaiter) event(e types.StackEvent) {
if w.isDone() {
return
}
w.events <- e
}

func (w *StackWaiter) pollEvents() {
ts := time.Now()
ticker := time.NewTicker(time.Second)
ts := time.Now()
for {
select {
case <-ticker.C:
es, _ := w.cloudFormation.stackEvents(w.stackName, &ts)
for _, e := range es {
w.event(e)
w.events <- e
}
if len(es) > 0 {
ts = *es[0].Timestamp
}
case <-w.done:
ticker.Stop()
close(w.events)
close(w.loopDone)
return
}
}
}

func (w *StackWaiter) isDone() bool {
select {
case <-w.done:
return true
default:
return false
}
}
9 changes: 5 additions & 4 deletions cli/ui/progress/elements.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package progress
import (
"fmt"
"strings"
"sync"
"time"
)

Expand All @@ -17,6 +18,7 @@ type Dots struct {
currentCnt int
updateCh chan struct{}
done chan struct{}
closer sync.Once
}

func NewDots() *Dots {
Expand Down Expand Up @@ -44,10 +46,9 @@ func (d *Dots) loop() {
}

func (d *Dots) Stop() {
if d.isDone() {
return
}
close(d.done)
d.closer.Do(func() {
close(d.done)
})
}

func (d *Dots) UpdateChan() <-chan struct{} {
Expand Down
9 changes: 5 additions & 4 deletions cli/ui/progress/progress.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"os"
"reflect"
"strings"
"sync"

"github.com/fatih/color"
)
Expand All @@ -16,6 +17,7 @@ type Progress struct {
loopDone chan struct{}
printFunc func(format string, v ...interface{})
isTerminal bool
closer sync.Once
}

func New(prefix string, printFunc func(format string, v ...interface{}), elements ...Element) *Progress {
Expand All @@ -42,10 +44,9 @@ func (p *Progress) Run() {
}

func (p *Progress) Stop() {
if p.isDone() {
return
}
close(p.done)
p.closer.Do(func() {
close(p.done)
})
<-p.loopDone
}

Expand Down
19 changes: 0 additions & 19 deletions cli/ui/progress/terraform.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,12 @@ type Terraform struct {
parser *terraform.Parser
progress *Progress
counter *Counter
done chan struct{}
}

func NewTerraform() *Terraform {
parser := terraform.NewLogParser()
p := &Terraform{
parser: parser,
done: make(chan struct{}),
}
return p
}
Expand All @@ -42,7 +40,6 @@ func (p *Terraform) checkState(oldState terraform.ParserState) {
fmt.Println()
}
if newState == terraform.StateDone {
p.close()
return
}
p.initProgress()
Expand All @@ -66,19 +63,3 @@ func (p *Terraform) updateCounter() {
}
p.counter.SetCount(p.parser.CurrentResourceCount())
}

func (p *Terraform) close() {
if p.isDone() {
return
}
close(p.done)
}

func (p *Terraform) isDone() bool {
select {
case <-p.done:
return true
default:
return false
}
}

0 comments on commit 6c87c3e

Please sign in to comment.