diff --git a/pkg/commands/container.go b/pkg/commands/container.go index b45feef78..132e4db36 100644 --- a/pkg/commands/container.go +++ b/pkg/commands/container.go @@ -140,7 +140,9 @@ func (c *Container) RenderTop(ctx context.Context) (string, error) { return utils.RenderTable(append([][]string{result.Titles}, result.Processes...)) } -// DetailsLoaded tells us whether we have yet loaded the details for a container. Because this is an asynchronous operation, sometimes we have the container before we have its details. +// DetailsLoaded tells us whether we have yet loaded the details for a container. +// Sometimes it takes some time for a container to have its details loaded +// after it starts. func (c *Container) DetailsLoaded() bool { return c.Details.ContainerJSONBase != nil } diff --git a/pkg/commands/docker.go b/pkg/commands/docker.go index e96c96533..7e4b3c5b6 100644 --- a/pkg/commands/docker.go +++ b/pkg/commands/docker.go @@ -10,6 +10,7 @@ import ( "os" "os/exec" "strings" + "sync" "time" cliconfig "github.com/docker/cli/cli/config" @@ -209,7 +210,7 @@ func (c *DockerCommand) GetContainers(existingContainers []*Container) ([]*Conta for i, container := range containers { var newContainer *Container - // check if we already data stored against the container + // check if we already have data stored against the container for _, existingContainer := range existingContainers { if existingContainer.ID == container.ID { newContainer = existingContainer @@ -244,6 +245,8 @@ func (c *DockerCommand) GetContainers(existingContainers []*Container) ([]*Conta ownContainers[i] = newContainer } + c.SetContainerDetails(ownContainers) + return ownContainers, nil } @@ -278,24 +281,35 @@ func (c *DockerCommand) GetServices() ([]*Service, error) { return services, nil } -// UpdateContainerDetails attaches the details returned from docker inspect to each of the containers -// this contains a bit more info than what you get from the go-docker client -func (c *DockerCommand) UpdateContainerDetails(containers []*Container) error { +func (c *DockerCommand) RefreshContainerDetails(containers []*Container) error { c.ContainerMutex.Lock() defer c.ContainerMutex.Unlock() - for _, container := range containers { - details, err := c.Client.ContainerInspect(context.Background(), container.ID) - if err != nil { - c.Log.Error(err) - } else { - container.Details = details - } - } + c.SetContainerDetails(containers) return nil } +// Attaches the details returned from docker inspect to each of the containers +// this contains a bit more info than what you get from the go-docker client +func (c *DockerCommand) SetContainerDetails(containers []*Container) { + wg := sync.WaitGroup{} + for _, container := range containers { + container := container + wg.Add(1) + go func() { + details, err := c.Client.ContainerInspect(context.Background(), container.ID) + if err != nil { + c.Log.Error(err) + } else { + container.Details = details + } + wg.Done() + }() + } + wg.Wait() +} + // ViewAllLogs attaches to a subprocess viewing all the logs from docker-compose func (c *DockerCommand) ViewAllLogs() (*exec.Cmd, error) { cmd := c.OSCommand.ExecutableFromString( diff --git a/pkg/gui/container_logs.go b/pkg/gui/container_logs.go index bb2feb850..2a1d4ecc5 100644 --- a/pkg/gui/container_logs.go +++ b/pkg/gui/container_logs.go @@ -114,10 +114,29 @@ func (gui *Gui) writeContainerLogs(container *commands.Container, ctx context.Co Follow: true, }) if err != nil { + gui.Log.Error(err) return err } + defer readCloser.Close() + + if !container.DetailsLoaded() { + // loop until the details load or context is cancelled, using timer + ticker := time.NewTicker(time.Millisecond * 100) + defer ticker.Stop() + outer: + for { + select { + case <-ctx.Done(): + return nil + case <-ticker.C: + if container.DetailsLoaded() { + break outer + } + } + } + } - if container.DetailsLoaded() && container.Details.Config.Tty { + if container.Details.Config.Tty { _, err = io.Copy(writer, readCloser) if err != nil { return err diff --git a/pkg/gui/gui.go b/pkg/gui/gui.go index 4797fb7f5..bf00fdd71 100644 --- a/pkg/gui/gui.go +++ b/pkg/gui/gui.go @@ -176,11 +176,9 @@ func (gui *Gui) goEvery(interval time.Duration, function func() error) { ticker := time.NewTicker(interval) defer ticker.Stop() for range ticker.C { - if gui.PauseBackgroundThreads { - return + if !gui.PauseBackgroundThreads { + _ = function() } - - _ = function() } }() } @@ -294,7 +292,7 @@ func (gui *Gui) setPanels() { } func (gui *Gui) updateContainerDetails() error { - return gui.DockerCommand.UpdateContainerDetails(gui.Panels.Containers.List.GetAllItems()) + return gui.DockerCommand.RefreshContainerDetails(gui.Panels.Containers.List.GetAllItems()) } func (gui *Gui) refresh() { diff --git a/pkg/tasks/tasks.go b/pkg/tasks/tasks.go index e6b9d4aca..06fac38f4 100644 --- a/pkg/tasks/tasks.go +++ b/pkg/tasks/tasks.go @@ -65,9 +65,12 @@ func (t *TaskManager) NewTask(f func(ctx context.Context)) error { t.waitingMutex.Lock() defer t.waitingMutex.Unlock() + t.taskIDMutex.Lock() if taskID < t.newTaskId { + t.taskIDMutex.Unlock() return } + t.taskIDMutex.Unlock() ctx, cancel := context.WithCancel(context.Background()) notifyStopped := make(chan struct{})