Merge pull request #4730 from thaJeztah/fix_stats_hang

prevent "docker stats" from hanging if the initial API call fails
This commit is contained in:
Sebastiaan van Stijn 2023-12-20 17:38:29 +01:00 committed by GitHub
commit 05a2dc401f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 20 additions and 25 deletions

View File

@ -135,24 +135,6 @@ func runStats(ctx context.Context, dockerCLI command.Cli, options *statsOptions)
} }
} }
// getContainerList simulates creation event for all previously existing
// containers (only used when calling `docker stats` without arguments).
getContainerList := func() {
cs, err := apiClient.ContainerList(ctx, container.ListOptions{
All: options.all,
})
if err != nil {
closeChan <- err
}
for _, ctr := range cs {
s := NewStats(ctr.ID[:12])
if cStats.add(s) {
waitFirst.Add(1)
go collect(ctx, s, apiClient, !options.noStream, waitFirst)
}
}
}
eventChan := make(chan events.Message) eventChan := make(chan events.Message)
go eh.Watch(eventChan) go eh.Watch(eventChan)
stopped := make(chan struct{}) stopped := make(chan struct{})
@ -160,17 +142,30 @@ func runStats(ctx context.Context, dockerCLI command.Cli, options *statsOptions)
defer close(stopped) defer close(stopped)
<-started <-started
// Start a short-lived goroutine to retrieve the initial list of // Fetch the initial list of containers and collect stats for them.
// containers. // After the initial list was collected, we start listening for events
getContainerList() // to refresh the list of containers.
cs, err := apiClient.ContainerList(ctx, container.ListOptions{
All: options.all,
})
if err != nil {
return err
}
for _, ctr := range cs {
s := NewStats(ctr.ID[:12])
if cStats.add(s) {
waitFirst.Add(1)
go collect(ctx, s, apiClient, !options.noStream, waitFirst)
}
}
// make sure each container get at least one valid stat data // make sure each container get at least one valid stat data
waitFirst.Wait() waitFirst.Wait()
} else { } else {
// Artificially send creation events for the containers we were asked to // Create the list of containers, and start collecting stats for all
// monitor (same code path than we use when monitoring all containers). // containers passed.
for _, name := range options.containers { for _, ctr := range options.containers {
s := NewStats(name) s := NewStats(ctr)
if cStats.add(s) { if cStats.add(s) {
waitFirst.Add(1) waitFirst.Add(1)
go collect(ctx, s, apiClient, !options.noStream, waitFirst) go collect(ctx, s, apiClient, !options.noStream, waitFirst)