Skip to content

Commit

Permalink
fix deadlock collecting large logs
Browse files Browse the repository at this point in the history
Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
  • Loading branch information
ndeloof committed Feb 13, 2024
1 parent 894ab41 commit 0d6efaa
Showing 1 changed file with 22 additions and 17 deletions.
39 changes: 22 additions & 17 deletions pkg/compose/printer.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,18 +32,19 @@ type logPrinter interface {
}

type printer struct {
sync.Mutex
queue chan api.ContainerEvent
consumer api.LogConsumer
stopped bool
stopCh chan struct{}
stop sync.Once
}

// newLogPrinter builds a LogPrinter passing containers logs to LogConsumer
func newLogPrinter(consumer api.LogConsumer) logPrinter {
queue := make(chan api.ContainerEvent)
printer := printer{
consumer: consumer,
queue: queue,
queue: make(chan api.ContainerEvent),
stopCh: make(chan struct{}),
stop: sync.Once{},
}
return &printer
}
Expand All @@ -54,24 +55,26 @@ func (p *printer) Cancel() {
}

func (p *printer) Stop() {
p.Lock()
defer p.Unlock()
if !p.stopped {
// only close if this is the first call to stop
p.stopped = true
close(p.queue)
}
p.stop.Do(func() {
close(p.stopCh)
for {
select {
case <-p.queue:
// purge the queue
default:
return
}
}
})
}

func (p *printer) HandleEvent(event api.ContainerEvent) {
p.Lock()
defer p.Unlock()
if p.stopped {
// prevent deadlocking, if the printer is done, there's no reader for
// queue, so this write could block indefinitely
select {
case <-p.stopCh:
return
default:
p.queue <- event
}
p.queue <- event
}

//nolint:gocyclo
Expand All @@ -80,6 +83,8 @@ func (p *printer) Run(cascadeStop bool, exitCodeFrom string, stopFn func() error
aborting bool
exitCode int
)
defer p.Stop()

containers := map[string]struct{}{}
for event := range p.queue {
container, id := event.Container, event.ID
Expand Down

0 comments on commit 0d6efaa

Please sign in to comment.